Backed out 4 changesets from bug 1454598 (26e036b1c703, bc910e36a7d7, bac001216577, 5af215d265b6) due to macOS 10.12 font issues.
authorJonathan Kew <jkew@mozilla.com>
Wed, 25 Apr 2018 10:18:07 +0100
changeset 415623 aa4185068f2e3ffb1377afa0e0d95b3c5ac0a04c
parent 415622 ff274dd24756e046c25bf37451fa77286c7ce737
child 415624 6696fd50114a8c105771f1e87e0b76cbf5761c26
push id33901
push userapavel@mozilla.com
push dateThu, 26 Apr 2018 06:05:37 +0000
treeherdermozilla-central@b62ad926cf2a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
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
Backed out 4 changesets from bug 1454598 (26e036b1c703, bc910e36a7d7, bac001216577, 5af215d265b6) due to macOS 10.12 font issues.
accessible/base/TextAttrs.cpp
dom/ipc/PContent.ipdl
gfx/src/FontPropertyTypes.h
gfx/src/nsFont.cpp
gfx/thebes/gfxDWriteFontList.cpp
gfx/thebes/gfxDWriteFontList.h
gfx/thebes/gfxDWriteFonts.cpp
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/gfxFontUtils.cpp
gfx/thebes/gfxFontUtils.h
gfx/thebes/gfxGDIFont.cpp
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/accessible/base/TextAttrs.cpp
+++ b/accessible/base/TextAttrs.cpp
@@ -651,20 +651,19 @@ TextAttrsMgr::FontWeightTextAttr::
     return FontWeight::Bold();
   }
 
   // On Windows, font->GetStyle()->weight will give the same weight as
   // fontEntry->Weight(), the weight of the first font in the font group,
   // which may not be the weight of the font face used to render the
   // characters. On Mac, font->GetStyle()->weight will just give the same
   // number as getComputedStyle(). fontEntry->Weight() will give the weight
-  // range supported by the font face used, so we clamp the weight that was
-  // requested by style to what is actually supported by the font.
+  // of the font face used.
   gfxFontEntry *fontEntry = font->GetFontEntry();
-  return fontEntry->Weight().Clamp(font->GetStyle()->weight);
+  return fontEntry->Weight();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // AutoGeneratedTextAttr
 ////////////////////////////////////////////////////////////////////////////////
 TextAttrsMgr::AutoGeneratedTextAttr::
   AutoGeneratedTextAttr(HyperTextAccessible* aHyperTextAcc,
                         Accessible* aAccessible) :
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -112,19 +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;
-    uint32_t  weightRange;
-    uint32_t  stretchRange;
-    uint32_t  styleRange;
+    float     weight;
+    int16_t   stretch;
+    uint8_t   italic;
     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
@@ -3,27 +3,20 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* font specific types shared by both thebes and layout */
 
 #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"
+#include "nsStringFwd.h"
 
 /*
  * This file is separate from gfxFont.h so that layout can include it
  * without bringing in gfxFont.h and everything it includes.
  */
 
 namespace mozilla {
 
@@ -37,17 +30,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 gfxFontStyle;
+ * attributes reduces the memory footprint of gfxFontEntry and gfxFontSlantStyle;
  * 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
 {
@@ -57,17 +50,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;
@@ -92,20 +85,19 @@ 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.
-  /// (Do not try to interpret the numeric value of this.)
-  uint16_t ForHash() const
+  InternalType ForHash() const
   {
-    return uint16_t(mValue);
+    return 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.
@@ -189,21 +181,19 @@ 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(); }
 
+private:
   typedef uint16_t InternalType;
 
-private:
-  friend class WeightRange;
-
   explicit FontWeight(InternalType aValue)
     : FontPropertyValue(aValue)
   {
   }
 
   static const InternalType kNormal        = 400u << kFractionBits;
   static const InternalType kBold          = 700u << kFractionBits;
   static const InternalType kBoldThreshold = 600u << kFractionBits;
@@ -272,21 +262,19 @@ public:
   static FontStretch UltraExpanded()
   {
     return FontStretch(kUltraExpanded);
   }
 
   bool IsNormal() const { return mValue == kNormal; }
   float Percentage() const { return ToFloat(); }
 
+private:
   typedef uint16_t InternalType;
 
-private:
-  friend class StretchRange;
-
   explicit FontStretch(InternalType aValue)
     : FontPropertyValue(aValue)
   {
   }
 
   static const InternalType kUltraCondensed =  50u << kFractionBits;
   static const InternalType kExtraCondensed = (62u << kFractionBits) + kPointFive;
   static const InternalType kCondensed      =  75u << kFractionBits;
@@ -305,16 +293,17 @@ 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()
@@ -327,270 +316,39 @@ 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)
   {
   }
 
   static const InternalType kNormal = INT16_MIN;
   static const InternalType kItalic = INT16_MAX;
 };
 
-
-/**
- * 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);
-  }
-
-  /**
-   * 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.)
-   */
-  T Clamp(T aValue) const
-  {
-    return aValue <= Min() ? Min() : (aValue >= Max() ? Max() : aValue);
-  }
-
-  /**
-   * Return whether the range consists of a single unique value.
-   */
-  bool IsSingle() const
-  {
-    return Min() == Max();
-  }
-
-  bool operator==(const FontPropertyRange& aOther) const
-  {
-    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.AppendFloat(Min().ToFloat());
-    if (!IsSingle()) {
-      aOutString.Append(aDelim);
-      aOutString.AppendFloat(Max().ToFloat());
-    }
-  }
-
-  static WeightRange FromScalar(ScalarType aScalar)
-  {
-    return WeightRange(FontWeight(FontWeight::InternalType(aScalar >> 16)),
-                       FontWeight(FontWeight::InternalType(aScalar & 0xffff)));
-  }
-};
-
-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,16 +287,19 @@ 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
@@ -185,19 +185,16 @@ gfxDWriteFontFamily::FindStyleVariations
         // <em> and <i> should be rendered as italic in the default style.
         if (fullID.EqualsLiteral("Meiryo Italic") ||
             fullID.EqualsLiteral("Meiryo Bold Italic")) {
             continue;
         }
 
         gfxDWriteFontEntry *fe = new gfxDWriteFontEntry(fullID, font, mIsSystemFontFamily);
         fe->SetForceGDIClassic(mForceGDIClassic);
-
-        fe->SetupVariationRanges();
-
         AddFontEntry(fe);
 
         // postscript/fullname if needed
         nsAutoString psname, fullname;
         if (fontInfoShouldHaveFaceNames) {
             aFontInfoData->GetFaceNames(fe->Name(), fullname, psname);
             if (!fullname.IsEmpty()) {
                 fp->AddFullname(fe, fullname);
@@ -217,26 +214,23 @@ gfxDWriteFontFamily::FindStyleVariations
             if (FAILED(hr)) {
                 skipFaceNames = true;
             } else if (fullname.Length() > 0) {
                 fp->AddFullname(fe, fullname);
             }
         }
 
         if (LOG_FONTLIST_ENABLED()) {
-            nsAutoCString weightString;
-            fe->Weight().ToString(weightString);
             LOG_FONTLIST(("(fontlist) added (%s) to family (%s)"
-                 " with style: %s weight: %s stretch: %d psname: %s fullname: %s",
+                 " with style: %s weight: %g stretch: %d psname: %s fullname: %s",
                  NS_ConvertUTF16toUTF8(fe->Name()).get(),
                  NS_ConvertUTF16toUTF8(Name()).get(),
                  (fe->IsItalic()) ?
                   "italic" : (fe->IsOblique() ? "oblique" : "normal"),
-                 weightString.get(),
-                 fe->Stretch(),
+                 fe->Weight().ToFloat(), fe->Stretch(),
                  NS_ConvertUTF16toUTF8(psname).get(),
                  NS_ConvertUTF16toUTF8(fullname).get()));
         }
     }
 
     // assume that if no error, all postscript/fullnames were initialized
     if (!skipFaceNames) {
         mFaceNamesInitialized = true;
@@ -371,21 +365,17 @@ gfxDWriteFontFamily::AddSizeOfIncludingT
 
 ////////////////////////////////////////////////////////////////////////////////
 // gfxDWriteFontEntry
 
 gfxFontEntry*
 gfxDWriteFontEntry::Clone() const
 {
     MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!");
-    gfxDWriteFontEntry* fe = new gfxDWriteFontEntry(Name(), mFont);
-    fe->mWeightRange = mWeightRange;
-    fe->mStretchRange = mStretchRange;
-    fe->mStyleRange = mStyleRange;
-    return fe;
+    return new gfxDWriteFontEntry(Name(), mFont);
 }
 
 gfxDWriteFontEntry::~gfxDWriteFontEntry()
 {
 }
 
 static bool
 UsingArabicOrHebrewScriptSystemLocale()
@@ -674,46 +664,46 @@ gfxDWriteFontEntry::CreateFontInstance(c
     DWRITE_FONT_SIMULATIONS sims =
         aNeedsBold ? DWRITE_FONT_SIMULATIONS_BOLD : DWRITE_FONT_SIMULATIONS_NONE;
     if (HasVariations() && !aFontStyle->variationSettings.IsEmpty()) {
         // If we need to apply variations, we can't use the cached mUnscaledFont
         // or mUnscaledFontBold here.
         // XXX todo: consider caching a small number of variation instances?
         RefPtr<IDWriteFontFace> fontFace;
         nsresult rv = CreateFontFace(getter_AddRefs(fontFace),
-                                     aFontStyle,
+                                     &aFontStyle->variationSettings,
                                      sims);
         if (NS_FAILED(rv)) {
             return nullptr;
         }
         RefPtr<UnscaledFontDWrite> unscaledFont =
             new UnscaledFontDWrite(fontFace, mIsSystemFont ? mFont : nullptr, sims);
         return new gfxDWriteFont(unscaledFont, this, aFontStyle, aNeedsBold);
     }
 
     ThreadSafeWeakPtr<UnscaledFontDWrite>& unscaledFontPtr =
         aNeedsBold ? mUnscaledFontBold : mUnscaledFont;
     RefPtr<UnscaledFontDWrite> unscaledFont(unscaledFontPtr);
     if (!unscaledFont) {
         RefPtr<IDWriteFontFace> fontFace;
-        nsresult rv = CreateFontFace(getter_AddRefs(fontFace), aFontStyle, sims);
+        nsresult rv = CreateFontFace(getter_AddRefs(fontFace), nullptr, sims);
         if (NS_FAILED(rv)) {
             return nullptr;
         }
         unscaledFont =
             new UnscaledFontDWrite(fontFace,
                                    mIsSystemFont ? mFont : nullptr, sims);
         unscaledFontPtr = unscaledFont;
     }
     return new gfxDWriteFont(unscaledFont, this, aFontStyle, aNeedsBold);
 }
 
 nsresult
 gfxDWriteFontEntry::CreateFontFace(IDWriteFontFace **aFontFace,
-                                   const gfxFontStyle* aFontStyle,
+                                   const nsTArray<gfxFontVariation>* aVariations,
                                    DWRITE_FONT_SIMULATIONS aSimulations)
 {
     // Convert an OpenType font tag from our uint32_t representation
     // (as constructed by TRUETYPE_TAG(...)) to the order DWrite wants.
     auto makeDWriteAxisTag = [](uint32_t aTag) {
         return DWRITE_MAKE_FONT_AXIS_TAG((aTag >> 24) & 0xff,
                                          (aTag >> 16) & 0xff,
                                          (aTag >> 8) & 0xff,
@@ -771,38 +761,46 @@ 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 && (HasVariations() || needSimulations)) {
+    if (mFontFace5 && (aVariations && !aVariations->IsEmpty() ||
+                       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;
-        GetVariationsForStyle(vars, *aFontStyle);
-
-        // Copy variation settings to DWrite's type.
-        if (!vars.IsEmpty()) {
-            for (const auto& v : vars) {
+        if (aVariations) {
+            // Merge mVariationSettings and *aVariations if both present
+            const nsTArray<gfxFontVariation>* vars;
+            AutoTArray<gfxFontVariation,4> mergedSettings;
+            if (!aVariations) {
+                vars = &mVariationSettings;
+            } else  {
+                if (mVariationSettings.IsEmpty()) {
+                    vars = aVariations;
+                } else {
+                    gfxFontUtils::MergeVariations(mVariationSettings,
+                                                  *aVariations,
+                                                  &mergedSettings);
+                    vars = &mergedSettings;
+                }
+            }
+            for (const auto& v : *vars) {
                 DWRITE_FONT_AXIS_VALUE axisValue = {
                     makeDWriteAxisTag(v.mTag),
                     v.mValue
                 };
                 fontAxisValues.AppendElement(axisValue);
             }
         }
-
         IDWriteFontFace5* ff5;
         resource->CreateFontFace(aSimulations,
                                  fontAxisValues.Elements(),
                                  fontAxisValues.Length(),
                                  &ff5);
         if (ff5) {
             *aFontFace = ff5;
         }
@@ -954,43 +952,43 @@ gfxDWriteFontList::GetDefaultFontForPlat
         }
     }
 
     return nullptr;
 }
 
 gfxFontEntry *
 gfxDWriteFontList::LookupLocalFont(const nsAString& aFontName,
-                                   WeightRange aWeightForEntry,
-                                   StretchRange aStretchForEntry,
-                                   SlantStyleRange aStyleForEntry)
+                                   FontWeight aWeight,
+                                   FontStretch aStretch,
+                                   FontSlantStyle aStyle)
 {
     gfxFontEntry *lookup;
 
     lookup = LookupInFaceNameLists(aFontName);
     if (!lookup) {
         return nullptr;
     }
 
     gfxDWriteFontEntry* dwriteLookup = static_cast<gfxDWriteFontEntry*>(lookup);
     gfxDWriteFontEntry *fe =
         new gfxDWriteFontEntry(lookup->Name(),
                                dwriteLookup->mFont,
-                               aWeightForEntry,
-                               aStretchForEntry,
-                               aStyleForEntry);
+                               aWeight,
+                               aStretch,
+                               aStyle);
     fe->SetForceGDIClassic(dwriteLookup->GetForceGDIClassic());
     return fe;
 }
 
 gfxFontEntry *
 gfxDWriteFontList::MakePlatformFont(const nsAString& aFontName,
-                                    WeightRange aWeightForEntry,
-                                    StretchRange aStretchForEntry,
-                                    SlantStyleRange aStyleForEntry,
+                                    FontWeight aWeight,
+                                    FontStretch aStretch,
+                                    FontSlantStyle aStyle,
                                     const uint8_t* aFontData,
                                     uint32_t aLength)
 {
     RefPtr<IDWriteFontFileStream> fontFileStream;
     RefPtr<IDWriteFontFile> fontFile;
     HRESULT hr =
       gfxDWriteFontFileLoader::CreateCustomFontFile(aFontData, aLength,
                                                     getter_AddRefs(fontFile),
@@ -1010,19 +1008,19 @@ gfxDWriteFontList::MakePlatformFont(cons
     BOOL isSupported;
     DWRITE_FONT_FILE_TYPE fileType;
     UINT32 numFaces;
 
     gfxDWriteFontEntry *entry = 
         new gfxDWriteFontEntry(uniqueName,
                                fontFile,
                                fontFileStream,
-                               aWeightForEntry,
-                               aStretchForEntry,
-                               aStyleForEntry);
+                               aWeight,
+                               aStretch,
+                               aStyle);
 
     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;
     }
 
@@ -1148,26 +1146,23 @@ gfxDWriteFontList::InitFontListForPlatfo
             // add faces to Gill Sans MT
             for (i = 0; i < faces.Length(); i++) {
                 // change the entry's family name to match its adoptive family
                 faces[i]->mFamilyName = gillSansMTFamily->Name();
                 gillSansMTFamily->AddFontEntry(faces[i]);
 
                 if (LOG_FONTLIST_ENABLED()) {
                     gfxFontEntry *fe = faces[i];
-                    nsAutoCString weightString;
-                    fe->Weight().ToString(weightString);
                     LOG_FONTLIST(("(fontlist) moved (%s) to family (%s)"
-                         " with style: %s weight: %s stretch: %d",
+                         " with style: %s weight: %g stretch: %d",
                          NS_ConvertUTF16toUTF8(fe->Name()).get(),
                          NS_ConvertUTF16toUTF8(gillSansMTFamily->Name()).get(),
                          (fe->IsItalic()) ?
                           "italic" : (fe->IsOblique() ? "oblique" : "normal"),
-                         weightString.get(),
-                         fe->Stretch()));
+                         fe->Weight().ToFloat(), fe->Stretch()));
                 }
             }
 
             // remove Gills Sans
             mFontFamilies.Remove(nameGillSans);
         }
     }
 
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -110,30 +110,25 @@ 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();
-        FontSlantStyle style =
-            (dwriteStyle == DWRITE_FONT_STYLE_ITALIC
-                ? FontSlantStyle::Italic()
-                : (dwriteStyle == DWRITE_FONT_STYLE_OBLIQUE
-                    ? FontSlantStyle::Oblique()
-                    : FontSlantStyle::Normal()));
-        mStyleRange = SlantStyleRange(style);
+        mStyle = (dwriteStyle == DWRITE_FONT_STYLE_ITALIC ?
+                  FontSlantStyle::Italic() :
+                  (dwriteStyle == DWRITE_FONT_STYLE_OBLIQUE ?
+                   FontSlantStyle::Oblique() : FontSlantStyle::Normal()));
+        mStretch = FontStretchFromDWriteStretch(aFont->GetStretch());
+        int weight = NS_ROUNDUP(aFont->GetWeight() - 50, 100);
 
-        mStretchRange =
-            StretchRange(FontStretchFromDWriteStretch(aFont->GetStretch()));
-
-        int weight = NS_ROUNDUP(aFont->GetWeight() - 50, 100);
         weight = mozilla::Clamp(weight, 100, 900);
-        mWeightRange = WeightRange(FontWeight(weight));
+        mWeight = FontWeight(weight);
 
         mIsCJK = UNINITIALIZED_VALUE;
     }
 
     /**
      * Constructs a font entry using a font. But with custom font values.
      * This is used for creating correct font entries for @font-face with local
      * font source.
@@ -141,26 +136,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,
-                       WeightRange aWeight,
-                       StretchRange aStretch,
-                       SlantStyleRange aStyle)
+                       FontWeight aWeight,
+                       FontStretch aStretch,
+                       FontSlantStyle aStyle)
       : gfxFontEntry(aFaceName), mFont(aFont), mFontFile(nullptr),
         mIsSystemFont(false), mForceGDIClassic(false),
         mHasVariations(false), mHasVariationsInitialized(false)
     {
-        mWeightRange = aWeight;
-        mStretchRange = aStretch;
-        mStyleRange = aStyle;
+        mWeight = aWeight;
+        mStretch = aStretch;
+        mStyle = aStyle;
         mIsLocalUserFont = true;
         mIsCJK = UNINITIALIZED_VALUE;
     }
 
     /**
      * Constructs a font entry using a font file.
      *
      * \param aFaceName The name of the corresponding font face.
@@ -168,27 +163,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,
-                              WeightRange aWeight,
-                              StretchRange aStretch,
-                              SlantStyleRange aStyle)
+                              FontWeight aWeight,
+                              FontStretch aStretch,
+                              FontSlantStyle aStyle)
       : gfxFontEntry(aFaceName), mFont(nullptr),
         mFontFile(aFontFile), mFontFileStream(aFontFileStream),
         mIsSystemFont(false), mForceGDIClassic(false),
         mHasVariations(false), mHasVariationsInitialized(false)
     {
-        mWeightRange = aWeight;
-        mStretchRange = aStretch;
-        mStyleRange = aStyle;
+        mWeight = aWeight;
+        mStretch = aStretch;
+        mStyle = aStyle;
         mIsDataUserFont = true;
         mIsCJK = UNINITIALIZED_VALUE;
     }
 
     gfxFontEntry* Clone() const override;
 
     virtual ~gfxDWriteFontEntry();
 
@@ -217,17 +212,17 @@ protected:
     virtual nsresult CopyFontTable(uint32_t aTableTag,
                                    nsTArray<uint8_t>& aBuffer) override;
 
     virtual gfxFont *CreateFontInstance(const gfxFontStyle *aFontStyle,
                                         bool aNeedsBold);
     
     nsresult CreateFontFace(
         IDWriteFontFace **aFontFace,
-        const gfxFontStyle* aFontStyle = nullptr,
+        const nsTArray<gfxFontVariation>* aVariations = nullptr,
         DWRITE_FONT_SIMULATIONS aSimulations = DWRITE_FONT_SIMULATIONS_NONE);
 
     static bool InitLogFont(IDWriteFont *aFont, LOGFONTW *aLogFont);
 
     /**
      * A fontentry only needs to have either of these. If it has both only
      * the IDWriteFont will be used.
      */
@@ -405,24 +400,24 @@ public:
     }
 
     // initialize font lists
     virtual nsresult InitFontListForPlatform() override;
 
     gfxFontFamily* CreateFontFamily(const nsAString& aName) const override;
 
     virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
-                                          WeightRange aWeightForEntry,
-                                          StretchRange aStretchForEntry,
-                                          SlantStyleRange aStyleForEntry);
+                                          FontWeight aWeight,
+                                          FontStretch aStretch,
+                                          FontSlantStyle aStyle);
 
     virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
-                                           WeightRange aWeightForEntry,
-                                           StretchRange aStretchForEntry,
-                                           SlantStyleRange aStyleForEntry,
+                                           FontWeight aWeight,
+                                           FontStretch aStretch,
+                                           FontSlantStyle aStyle,
                                            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/gfxDWriteFonts.cpp
+++ b/gfx/thebes/gfxDWriteFonts.cpp
@@ -152,18 +152,17 @@ gfxDWriteFont::GetFakeMetricsForArialBla
 
     return true;
 }
 
 void
 gfxDWriteFont::ComputeMetrics(AntialiasOption anAAOption)
 {
     DWRITE_FONT_METRICS fontMetrics;
-    if (!(mFontEntry->Weight().Min() == FontWeight(900) &&
-          mFontEntry->Weight().Max() == FontWeight(900) &&
+    if (!(mFontEntry->Weight() == FontWeight(900) &&
           !mFontEntry->IsUserFont() &&
           mFontEntry->Name().EqualsLiteral("Arial Black") &&
           GetFakeMetricsForArialBlack(&fontMetrics)))
     {
         mFontFace->GetMetrics(&fontMetrics);
     }
 
     if (mStyle.sizeAdjust >= 0.0) {
--- a/gfx/thebes/gfxFT2FontBase.cpp
+++ b/gfx/thebes/gfxFT2FontBase.cpp
@@ -224,21 +224,33 @@ gfxFT2FontBase::InitMetrics()
         mMetrics.underlineOffset = -underlineSize;
         mMetrics.strikeoutOffset = 0.25 * emHeight;
         mMetrics.strikeoutSize = underlineSize;
 
         SanitizeMetrics(&mMetrics, false);
         return;
     }
 
-    if (face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS) {
+    if ((!mFontEntry->mVariationSettings.IsEmpty() ||
+         !mStyle.variationSettings.IsEmpty()) &&
+         (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);
+        const nsTArray<gfxFontVariation>* settings;
+        AutoTArray<gfxFontVariation,8> mergedSettings;
+        if (mFontEntry->mVariationSettings.IsEmpty()) {
+            settings = &mStyle.variationSettings;
+        } else if (mStyle.variationSettings.IsEmpty()) {
+            settings = &mFontEntry->mVariationSettings;
+        } else {
+            gfxFontUtils::MergeVariations(mFontEntry->mVariationSettings,
+                                          mStyle.variationSettings,
+                                          &mergedSettings);
+            settings = &mergedSettings;
+        }
+        SetupVarCoords(face, *settings, &mCoords);
         if (!mCoords.IsEmpty()) {
 #if MOZ_TREE_FREETYPE
             FT_Set_Var_Design_Coordinates(face, mCoords.Length(), mCoords.Elements());
 #else
             typedef FT_Error (*SetCoordsFunc)(FT_Face, FT_UInt, FT_Fixed*);
             static SetCoordsFunc setCoords;
             static bool firstTime = true;
             if (firstTime) {
--- a/gfx/thebes/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -219,19 +219,19 @@ 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->mStretchRange = mStretchRange;
-    fe->mStyleRange = mStyleRange;
+    fe->mWeight = mWeight;
+    fe->mStretch = mStretch;
+    fe->mStyle = mStyle;
     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,
-                              WeightRange aWeight,
-                              StretchRange aStretch,
-                              SlantStyleRange aStyle,
+                              FontWeight aWeight,
+                              FontStretch aStretch,
+                              FontSlantStyle 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->mStyleRange = aStyle;
-        fe->mWeightRange = aWeight;
-        fe->mStretchRange = aStretch;
+        fe->mStyle = aStyle;
+        fe->mWeight = aWeight;
+        fe->mStretch = aStretch;
         fe->mIsDataUserFont = true;
     }
     return fe;
 }
 
 class FTUserFontData {
 public:
     FTUserFontData(FT_Face aFace, const uint8_t* aData, uint32_t aLength)
@@ -323,19 +323,22 @@ FTFontDestroyFunc(void *data)
 
 /* static */
 FT2FontEntry*
 FT2FontEntry::CreateFontEntry(const FontListEntry& aFLE)
 {
     FT2FontEntry *fe = new FT2FontEntry(aFLE.faceName());
     fe->mFilename = aFLE.filepath();
     fe->mFTFontIndex = aFLE.index();
-    fe->mWeightRange = WeightRange::FromScalar(aFLE.weightRange());
-    fe->mStretchRange = StretchRange::FromScalar(aFLE.stretchRange());
-    fe->mStyleRange = SlantStyleRange::FromScalar(aFLE.styleRange());
+    // The weight transported across IPC is a float, so we need to explicitly
+    // convert it back to a FontWeight.
+    fe->mWeight = FontWeight(aFLE.weight());
+    fe->mStretch = FontStretch(float(aFLE.stretch()));
+    fe->mStyle = aFLE.italic()
+      ? FontSlantStyle::Italic() : FontSlantStyle::Normal();
     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);
@@ -383,20 +386,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->mStyleRange = SlantStyleRange(FTFaceIsItalic(aFace)
-                                      ? FontSlantStyle::Italic()
-                                      : FontSlantStyle::Normal());
-    fe->mWeightRange = WeightRange(FTFaceGetWeight(aFace));
+    fe->mStyle = (FTFaceIsItalic(aFace) ?
+                  FontSlantStyle::Italic() : FontSlantStyle::Normal());
+    fe->mWeight = FTFaceGetWeight(aFace);
     fe->mFilename = aFilename;
     fe->mFTFontIndex = aIndex;
 
     if (aFontData) {
         fe->mFTFace = aFace;
         int flags = gfxPlatform::GetPlatform()->FontHintingEnabled() ?
                     FT_LOAD_DEFAULT :
                     (FT_LOAD_NO_AUTOHINT | FT_LOAD_NO_HINTING);
@@ -459,20 +461,32 @@ FT2FontEntry::CairoFontFace(const gfxFon
     // have custom variation coordinates applied.
     if ((!mVariationSettings.IsEmpty() ||
         (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());
+        const nsTArray<gfxFontVariation>* settings;
+        AutoTArray<gfxFontVariation,8> mergedSettings;
+        if (aStyle) {
+            if (mVariationSettings.IsEmpty()) {
+                settings = &aStyle->variationSettings;
+            } else {
+                gfxFontUtils::MergeVariations(mVariationSettings,
+                                              aStyle->variationSettings,
+                                              &mergedSettings);
+                settings = &mergedSettings;
+            }
+        } else {
+            settings = &mVariationSettings;
+        }
         AutoTArray<FT_Fixed,8> coords;
-        gfxFT2FontBase::SetupVarCoords(mFTFace, settings, &coords);
+        gfxFT2FontBase::SetupVarCoords(mFTFace, *settings, &coords);
         // Create a separate FT_Face because we need to apply custom
         // variation settings to it.
         FT_Face ftFace;
         if (!mFilename.IsEmpty()) {
             ftFace = Factory::NewFTFace(nullptr, mFilename.get(), mFTFontIndex);
         } else {
             auto ufd = reinterpret_cast<FTUserFontData*>(
                 cairo_font_face_get_user_data(mFontFace, &sFTUserFontDataKey));
@@ -646,22 +660,26 @@ 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().AsScalar(),
-                                               fe->Stretch().AsScalar(),
-                                               fe->SlantStyle().AsScalar(),
+                                               fe->Weight().ToFloat(),
+                                               fe->Stretch().Percentage(),
+                                               fe->mStyle.IsItalic()
+                                                ? NS_FONT_STYLE_ITALIC
+                                                : NS_FONT_STYLE_NORMAL,
                                                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.
@@ -925,75 +943,44 @@ 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;
         }
-        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);
-        }
-
+        bool italic = (*beginning != '0');
         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;
-        }
-
+        uint32_t weight = strtoul(beginning, nullptr, 10);
         beginning = end + 1;
         if (!(end = strchr(beginning, ','))) {
             break;
         }
-        float minStretch = strtof(beginning, &limit);
-        float maxStretch;
-        if (*limit == ':' && limit + 1 < end) {
-            maxStretch = strtof(limit + 1, nullptr);
-        } else {
-            maxStretch = minStretch;
-        }
+        uint32_t stretch = strtoul(beginning, nullptr, 10);
 
-        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);
+        FontListEntry fle(familyName, faceName, aFileName,
+                          weight, stretch, italic, index);
         AppendFaceFromFontListEntry(fle, aStdFile);
 
         beginning = end + 1;
         end = strchr(beginning, ',');
     }
 }
 
 static void
@@ -1003,23 +990,20 @@ AppendToFaceList(nsCString& aFaceList,
     aFaceList.Append(NS_ConvertUTF16toUTF8(aFamilyName));
     aFaceList.Append(',');
     aFaceList.Append(NS_ConvertUTF16toUTF8(aFontEntry->Name()));
     aFaceList.Append(',');
     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.AppendFloat(aFontEntry->Weight().ToFloat());
     aFaceList.Append(',');
-    aFaceList.AppendFloat(aFontEntry->Stretch().Min().Percentage());
-    aFaceList.Append(':');
-    aFaceList.AppendFloat(aFontEntry->Stretch().Max().Percentage());
+    // FIXME(emilio): Probably the stretch should be converted to float.
+    aFaceList.AppendInt(int32_t(aFontEntry->Stretch().Percentage()));
     aFaceList.Append(',');
 }
 
 void
 FT2FontEntry::CheckForBrokenFont(gfxFontFamily *aFamily)
 {
     // note if the family is in the "bad underline" blacklist
     if (aFamily->IsBadUnderlineFamily()) {
@@ -1165,27 +1149,22 @@ gfxFT2FontList::AddFaceToList(const nsCS
         }
         fe->mStandardFace = (aStdFile == kStandard);
         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: %s",
+                 " with style: %s weight: %g stretch: %g%%",
                  NS_ConvertUTF16toUTF8(fe->Name()).get(),
                  NS_ConvertUTF16toUTF8(family->Name()).get(),
                  fe->IsItalic() ? "italic" : "normal",
-                 weightString.get(),
-                 stretchString.get()));
+                 fe->Weight().ToFloat(), fe->Stretch().Percentage()));
         }
     }
 }
 
 void
 gfxFT2FontList::AppendFacesFromOmnijarEntry(nsZipArchive* aArchive,
                                             const nsCString& aEntryName,
                                             FontNameCache *aCache,
@@ -1485,19 +1464,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,
-                                WeightRange aWeightForEntry,
-                                StretchRange aStretchForEntry,
-                                SlantStyleRange aStyleForEntry)
+                                FontWeight aWeight,
+                                FontStretch aStretch,
+                                FontSlantStyle aStyle)
 {
     // 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
@@ -1542,19 +1521,19 @@ searchDone:
     }
 
     FT2FontEntry* fe =
         FT2FontEntry::CreateFontEntry(fontEntry->mFTFace,
                                       fontEntry->mFilename.get(),
                                       fontEntry->mFTFontIndex,
                                       fontEntry->Name(), nullptr);
     if (fe) {
-        fe->mStyleRange = aStyleForEntry;
-        fe->mWeightRange = aWeightForEntry;
-        fe->mStretchRange = aStretchForEntry;
+        fe->mStyle = aStyle;
+        fe->mWeight = aWeight;
+        fe->mStretch = aStretch;
         fe->mIsLocalUserFont = true;
     }
 
     return fe;
 }
 
 gfxFontFamily*
 gfxFT2FontList::GetDefaultFontForPlatform(const gfxFontStyle* aStyle)
@@ -1567,30 +1546,27 @@ gfxFT2FontList::GetDefaultFontForPlatfor
     }
 #endif
     /* TODO: what about Qt or other platforms that may use this? */
     return ff;
 }
 
 gfxFontEntry*
 gfxFT2FontList::MakePlatformFont(const nsAString& aFontName,
-                                 WeightRange aWeightForEntry,
-                                 StretchRange aStretchForEntry,
-                                 SlantStyleRange aStyleForEntry,
+                                 FontWeight aWeight,
+                                 FontStretch aStretch,
+                                 FontSlantStyle aStyle,
                                  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,
-                                         aWeightForEntry,
-                                         aStretchForEntry,
-                                         aStyleForEntry,
-                                         aFontData, aLength);
+    return FT2FontEntry::CreateFontEntry(aFontName, aWeight, aStretch,
+                                         aStyle, 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,
-                    WeightRange aWeight,
-                    StretchRange aStretch,
-                    SlantStyleRange aStyle,
+                    FontWeight aWeight,
+                    FontStretch aStretch,
+                    FontSlantStyle 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,
-                                          WeightRange aWeightForEntry,
-                                          StretchRange aStretchForEntry,
-                                          SlantStyleRange aStyleForEntry) override;
+                                          FontWeight aWeight,
+                                          FontStretch aStretch,
+                                          FontSlantStyle aStyle) override;
 
     virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
-                                           WeightRange aWeightForEntry,
-                                           StretchRange aStretchForEntry,
-                                           SlantStyleRange aStyleForEntry,
+                                           FontWeight aWeight,
+                                           FontStretch aStretch,
+                                           FontSlantStyle aStyle,
                                            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
@@ -53,19 +53,16 @@ using namespace mozilla::gfx;
 using namespace mozilla::unicode;
 
 using mozilla::dom::SystemFontListEntry;
 using mozilla::dom::FontPatternListEntry;
 
 #ifndef FC_POSTSCRIPT_NAME
 #define FC_POSTSCRIPT_NAME  "postscriptname"      /* String */
 #endif
-#ifndef FC_VARIABLE
-#define FC_VARIABLE         "variable"            /* Bool */
-#endif
 
 #define PRINTING_FC_PROPERTY "gfx.printing"
 
 #define LOG_FONTLIST(args) MOZ_LOG(gfxPlatform::GetLog(eGfxLog_fontlist), \
                                LogLevel::Debug, args)
 #define LOG_FONTLIST_ENABLED() MOZ_LOG_TEST( \
                                    gfxPlatform::GetLog(eGfxLog_fontlist), \
                                    LogLevel::Debug)
@@ -231,43 +228,42 @@ MapFcWidth(int aFcWidth)
 }
 
 gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString& aFaceName,
                                                FcPattern* aFontPattern,
                                                bool aIgnoreFcCharmap)
         : gfxFontEntry(aFaceName), mFontPattern(aFontPattern),
           mFTFace(nullptr), mFTFaceInitialized(false),
           mIgnoreFcCharmap(aIgnoreFcCharmap),
-          mHasVariationsInitialized(false),
           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) {
-        mStyleRange = SlantStyleRange(FontSlantStyle::Oblique());
+        mStyle = FontSlantStyle::Oblique();
     } else if (slant > 0) {
-        mStyleRange = SlantStyleRange(FontSlantStyle::Italic());
+        mStyle = FontSlantStyle::Italic();
     }
 
     // weight
     int weight;
     if (FcPatternGetInteger(aFontPattern, FC_WEIGHT, 0, &weight) != FcResultMatch) {
         weight = FC_WEIGHT_REGULAR;
     }
-    mWeightRange = WeightRange(MapFcWeight(weight));
+    mWeight = MapFcWeight(weight);
 
     // width
     int width;
     if (FcPatternGetInteger(aFontPattern, FC_WIDTH, 0, &width) != FcResultMatch) {
         width = FC_WIDTH_NORMAL;
     }
-    mStretchRange = StretchRange(MapFcWidth(width));
+    mStretch = MapFcWidth(width);
 }
 
 gfxFontEntry*
 gfxFontconfigFontEntry::Clone() const
 {
     MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!");
     return new gfxFontconfigFontEntry(Name(), mFontPattern, mIgnoreFcCharmap);
 }
@@ -311,51 +307,49 @@ 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,
-                                               WeightRange aWeight,
-                                               StretchRange aStretch,
-                                               SlantStyleRange aStyle,
+                                               FontWeight aWeight,
+                                               FontStretch aStretch,
+                                               FontSlantStyle 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 = aWeight;
-    mStyleRange = aStyle;
-    mStretchRange = aStretch;
+    mWeight = aWeight;
+    mStyle = aStyle;
+    mStretch = aStretch;
     mIsDataUserFont = true;
 
     mFontPattern = CreatePatternForFace(mFTFace);
 
     mUserFontData = new FTUserFontData(mFTFace, mFontData);
 }
 
 gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString& aFaceName,
                                                FcPattern* aFontPattern,
-                                               WeightRange aWeight,
-                                               StretchRange aStretch,
-                                               SlantStyleRange aStyle)
+                                               FontWeight aWeight,
+                                               FontStretch aStretch,
+                                               FontSlantStyle aStyle)
         : gfxFontEntry(aFaceName), mFontPattern(aFontPattern),
           mFTFace(nullptr), mFTFaceInitialized(false),
-          mHasVariationsInitialized(false),
           mAspect(0.0), mFontData(nullptr), mLength(0)
 {
-    mWeightRange = aWeight;
-    mStyleRange = aStyle;
-    mStretchRange = aStretch;
+    mWeight = aWeight;
+    mStyle = aStyle;
+    mStretch = 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,22 +760,32 @@ 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 (HasVariations()) {
+    if (!aStyle->variationSettings.IsEmpty() || !mVariationSettings.IsEmpty()) {
         FT_Face ftFace = GetFTFace();
         if (ftFace) {
-            AutoTArray<gfxFontVariation,8> settings;
-            GetVariationsForStyle(settings, *aStyle);
-            gfxFT2FontBase::SetupVarCoords(ftFace, settings, &coords);
+            const nsTArray<gfxFontVariation>* settings;
+            AutoTArray<gfxFontVariation,8> mergedSettings;
+            if (mVariationSettings.IsEmpty()) {
+                settings = &aStyle->variationSettings;
+            } else if (aStyle->variationSettings.IsEmpty()) {
+                settings = &mVariationSettings;
+            } else {
+                gfxFontUtils::MergeVariations(mVariationSettings,
+                                              aStyle->variationSettings,
+                                              &mergedSettings);
+                settings = &mergedSettings;
+            }
+            gfxFT2FontBase::SetupVarCoords(ftFace, *settings, &coords);
         }
     }
 
     cairo_font_face_t *face =
         cairo_ft_font_face_create_for_pattern(aRenderPattern,
                                               coords.Elements(),
                                               coords.Length());
 
@@ -1055,38 +1059,21 @@ gfxFontconfigFontEntry::GetFTFace()
         mFTFace = CreateFaceForPattern(mFontPattern);
     }
     return mFTFace;
 }
 
 bool
 gfxFontconfigFontEntry::HasVariations()
 {
-    if (mHasVariationsInitialized) {
-        return mHasVariations;
+    FT_Face face = GetFTFace();
+    if (face) {
+        return face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS;
     }
-    mHasVariationsInitialized = true;
-    mHasVariations = false;
-
-    // For installed fonts, query the fontconfig pattern rather than paying
-    // the cost of loading a FT_Face that we otherwise might never need.
-    if (!IsUserFont() || IsLocalUserFont()) {
-        FcBool variable;
-        if ((FcPatternGetBool(mFontPattern, FC_VARIABLE, 0,
-                              &variable) == FcResultMatch) && variable) {
-            mHasVariations = true;
-        }
-    } else {
-        FT_Face face = GetFTFace();
-        if (face) {
-            mHasVariations = face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS;
-        }
-    }
-
-    return mHasVariations;
+    return false;
 }
 
 FT_MM_Var*
 gfxFontconfigFontEntry::GetMMVar()
 {
     if (mMMVarInitialized) {
         return mMMVar;
     }
@@ -1203,39 +1190,32 @@ gfxFontconfigFontFamily::FindStyleVariat
 
         // figure out the psname/fullname and choose which to use as the facename
         nsAutoString psname, fullname;
         GetFaceNames(face, mName, psname, fullname);
         const nsAutoString& faceName = !psname.IsEmpty() ? psname : fullname;
 
         gfxFontconfigFontEntry *fontEntry =
             new gfxFontconfigFontEntry(faceName, face, mContainsAppFonts);
-        fontEntry->SetupVariationRanges();
-
         AddFontEntry(fontEntry);
 
         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: %s"
+                 " with style: %s weight: %g stretch: %g%%"
                  " psname: %s fullname: %s",
                  NS_ConvertUTF16toUTF8(fontEntry->Name()).get(),
                  NS_ConvertUTF16toUTF8(Name()).get(),
-                 styleString.get(),
-                 weightString.get(),
-                 stretchString.get(),
+                 (fontEntry->IsItalic()) ?
+                  "italic" : (fontEntry->IsOblique() ? "oblique" : "normal"),
+                 fontEntry->Weight().ToFloat(),
+                 fontEntry->Stretch().Percentage(),
                  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) {
@@ -1331,17 +1311,17 @@ gfxFontconfigFontFamily::FindAllFontsFor
         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() != entry->Weight() ||
-            bestEntry->SlantStyle() != entry->SlantStyle()) {
+            bestEntry->mStyle != entry->mStyle) {
             // 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,59 +1854,54 @@ gfxFcPlatformFontList::GetDefaultFontFor
     if (prefFonts && !prefFonts->IsEmpty()) {
         return (*prefFonts)[0];
     }
     return nullptr;
 }
 
 gfxFontEntry*
 gfxFcPlatformFontList::LookupLocalFont(const nsAString& aFontName,
-                                       WeightRange aWeightForEntry,
-                                       StretchRange aStretchForEntry,
-                                       SlantStyleRange aStyleForEntry)
+                                       FontWeight aWeight,
+                                       FontStretch aStretch,
+                                       FontSlantStyle aStyle)
 {
     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,
-                                      aWeightForEntry,
-                                      aStretchForEntry,
-                                      aStyleForEntry);
+                                      aWeight, aStretch, aStyle);
 }
 
 gfxFontEntry*
 gfxFcPlatformFontList::MakePlatformFont(const nsAString& aFontName,
-                                        WeightRange aWeightForEntry,
-                                        StretchRange aStretchForEntry,
-                                        SlantStyleRange aStyleForEntry,
+                                        FontWeight aWeight,
+                                        FontStretch aStretch,
+                                        FontSlantStyle aStyle,
                                         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,
-                                      aWeightForEntry,
-                                      aStretchForEntry,
-                                      aStyleForEntry,
-                                      aFontData, aLength, face);
+    return new gfxFontconfigFontEntry(aFontName, aWeight, aStretch,
+                                      aStyle, aFontData, aLength, face);
 }
 
 bool
 gfxFcPlatformFontList::FindAndAddFamilies(const nsAString& aFamily,
                                           nsTArray<gfxFontFamily*>* aOutput,
                                           FindFamiliesFlags aFlags,
                                           gfxFontStyle* aStyle,
                                           gfxFloat aDevToCssSize)
@@ -2200,36 +2175,37 @@ gfxFcPlatformFontList::GetFTLibrary()
         // has been called on each FT_Face, at least until this bug is fixed:
         // https://bugs.freedesktop.org/show_bug.cgi?id=18857
         //
         // Cairo keeps it's own FT_Library object for creating FT_Face
         // instances, so use that. There's no simple API for accessing this
         // so use the hacky method below of making a font and extracting
         // the library pointer from that.
 
-        FcPattern* pat =
-            FcPatternBuild(0, FC_FAMILY, FcTypeString, "serif", (char*)0);
-        cairo_font_face_t* face =
-            cairo_ft_font_face_create_for_pattern(pat, nullptr, 0);
-        FcPatternDestroy(pat);
+        bool needsBold;
+        gfxFontStyle style;
+        gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
+        gfxFontFamily* family = pfl->GetDefaultFont(&style);
+        NS_ASSERTION(family, "couldn't find a default font family");
+        gfxFontEntry* fe = family->FindFontForStyle(style, needsBold, true);
+        if (!fe) {
+            return nullptr;
+        }
+        RefPtr<gfxFont> font = fe->FindOrMakeFont(&style, false);
+        if (!font) {
+            return nullptr;
+        }
 
-        cairo_matrix_t identity;
-        cairo_matrix_init_identity(&identity);
-        cairo_font_options_t* options = cairo_font_options_create();
-        cairo_scaled_font_t* sf =
-            cairo_scaled_font_create(face, &identity, &identity, options);
-        cairo_font_options_destroy(options);
-        cairo_font_face_destroy(face);
+        gfxFT2FontBase* ft2Font = reinterpret_cast<gfxFT2FontBase*>(font.get());
+        gfxFT2LockedFace face(ft2Font);
+        if (!face.get()) {
+            return nullptr;
+        }
 
-        FT_Face ft = cairo_ft_scaled_font_lock_face(sf);
-
-        sCairoFTLibrary = ft->glyph->library;
-
-        cairo_ft_scaled_font_unlock_face(sf);
-        cairo_scaled_font_destroy(sf);
+        sCairoFTLibrary = face.get()->glyph->library;
     }
 
     return sCairoFTLibrary;
 }
 
 gfxPlatformFontList::PrefFontList*
 gfxFcPlatformFontList::FindGenericFamilies(const nsAString& aGeneric,
                                            nsAtom* aLanguage)
--- 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,
-                                    WeightRange aWeight,
-                                    StretchRange aStretch,
-                                    SlantStyleRange aStyle,
+                                    FontWeight aWeight,
+                                    FontStretch aStretch,
+                                    FontSlantStyle 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,
-                                    WeightRange aWeight,
-                                    StretchRange aStretch,
-                                    SlantStyleRange aStyle);
+                                    FontWeight aWeight,
+                                    FontStretch aStretch,
+                                    FontSlantStyle aStyle);
 
     gfxFontEntry* Clone() const override;
 
     FcPattern* GetPattern() { return mFontPattern; }
 
     nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr) override;
     bool TestCharacterMap(uint32_t aCh) override;
 
@@ -163,23 +163,16 @@ protected:
 
     // Whether TestCharacterMap should check the actual cmap rather than asking
     // fontconfig about character coverage.
     // We do this for app-bundled (rather than system) fonts, as they may
     // include color glyphs that fontconfig would overlook, and for fonts
     // loaded via @font-face.
     bool      mIgnoreFcCharmap;
 
-    // Whether the face supports variations. For system-installed fonts, we
-    // query fontconfig for this (so they will only work if fontconfig is
-    // recent enough to include support); for downloaded user-fonts we query
-    // the FreeType face.
-    bool      mHasVariations;
-    bool      mHasVariationsInitialized;
-
     double    mAspect;
 
     // data font
     const uint8_t* mFontData;
     uint32_t       mLength;
 
     class UnscaledFontCache
     {
@@ -291,25 +284,25 @@ public:
                      const nsACString& aGenericFamily,
                      nsTArray<nsString>& aListOfFonts) override;
 
     void ReadSystemFontList(
         InfallibleTArray<mozilla::dom::SystemFontListEntry>* retValue);
 
     gfxFontEntry*
     LookupLocalFont(const nsAString& aFontName,
-                    WeightRange aWeightForEntry,
-                    StretchRange aStretchForEntry,
-                    SlantStyleRange aStyleForEntry) override;
+                    FontWeight aWeight,
+                    FontStretch aStretch,
+                    FontSlantStyle aStyle) override;
 
     gfxFontEntry*
     MakePlatformFont(const nsAString& aFontName,
-                     WeightRange aWeightForEntry,
-                     StretchRange aStretchForEntry,
-                     SlantStyleRange aStyleForEntry,
+                     FontWeight aWeight,
+                     FontStretch aStretch,
+                     FontSlantStyle aStyle,
                      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
@@ -75,19 +75,19 @@ gfxFontEntry::gfxFontEntry() :
     mGraphiteSpaceContextualsInitialized(false),
     mHasGraphiteSpaceContextuals(false),
     mSpaceGlyphIsInvisible(false),
     mSpaceGlyphIsInvisibleInitialized(false),
     mCheckedForGraphiteTables(false),
     mHasCmapTable(false),
     mGrFaceInitialized(false),
     mCheckedForColorGlyph(false),
-    mWeightRange(FontWeight(500)),
-    mStretchRange(FontStretch::Normal()),
-    mStyleRange(FontSlantStyle::Normal()),
+    mWeight(500),
+    mStretch(FontStretch::Normal()),
+    mStyle(FontSlantStyle::Normal()),
     mUVSOffset(0), mUVSData(nullptr),
     mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
     mCOLR(nullptr),
     mCPAL(nullptr),
     mUnitsPerEm(0),
     mHBFace(nullptr),
     mGrFace(nullptr),
     mGrFaceRefCnt(0),
@@ -114,19 +114,19 @@ gfxFontEntry::gfxFontEntry(const nsAStri
     mGraphiteSpaceContextualsInitialized(false),
     mHasGraphiteSpaceContextuals(false),
     mSpaceGlyphIsInvisible(false),
     mSpaceGlyphIsInvisibleInitialized(false),
     mCheckedForGraphiteTables(false),
     mHasCmapTable(false),
     mGrFaceInitialized(false),
     mCheckedForColorGlyph(false),
-    mWeightRange(FontWeight(500)),
-    mStretchRange(FontStretch::Normal()),
-    mStyleRange(FontSlantStyle::Normal()),
+    mWeight(500),
+    mStretch(FontStretch::Normal()),
+    mStyle(FontSlantStyle::Normal()),
     mUVSOffset(0), mUVSData(nullptr),
     mLanguageOverride(NO_FONT_LANGUAGE_OVERRIDE),
     mCOLR(nullptr),
     mCPAL(nullptr),
     mUnitsPerEm(0),
     mHBFace(nullptr),
     mGrFace(nullptr),
     mGrFaceRefCnt(0),
@@ -1027,133 +1027,16 @@ gfxFontEntry::GetColorLayersInfo(uint32_
     return gfxFontUtils::GetColorGlyphLayers(mCOLR,
                                              mCPAL,
                                              aGlyphId,
                                              aDefaultColor,
                                              aLayerGlyphs,
                                              aLayerColors);
 }
 
-void
-gfxFontEntry::SetupVariationRanges()
-{
-    if (!HasVariations() || IsUserFont()) {
-        return;
-    }
-    AutoTArray<gfxFontVariationAxis,4> axes;
-    GetVariationAxes(axes);
-    for (const auto& axis : axes) {
-        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.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)) {
-                if (FontWeight(axis.mDefaultValue) != Weight().Min()) {
-                    mStandardFace = false;
-                }
-                mWeightRange =
-                    WeightRange(FontWeight(std::max(1.0f, axis.mMinValue)),
-                                FontWeight(axis.mMaxValue));
-            }
-            break;
-
-        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.
-    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});
-    }
-
-    // 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());
-        if (index == aResult.NoIndex) {
-            aResult.AppendElement(aSetting);
-        } else {
-            aResult[index].mValue = aSetting.mValue;
-        }
-    };
-
-    // The low-level font-variation-settings descriptor from @font-face,
-    // if present, takes precedence over automatic variation settings
-    // from high-level properties.
-    for (const auto& v : mVariationSettings) {
-        replaceOrAppend(v);
-    }
-
-    // And the low-level font-variation-settings property takes precedence
-    // over the descriptor.
-    for (const auto& v : aStyle.variationSettings) {
-        replaceOrAppend(v);
-    }
-}
-
 size_t
 gfxFontEntry::FontTableHashEntry::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
 {
     size_t n = 0;
     if (mBlob) {
         n += aMallocSizeOf(mBlob);
     }
     if (mSharedBlobData) {
@@ -1290,179 +1173,135 @@ gfxFontFamily::FindFontForStyle(const gf
     FindAllFontsForStyle(aFontStyle, matched, aNeedsSyntheticBold,
                          aIgnoreSizeTolerance);
     if (!matched.IsEmpty()) {
         return matched[0];
     }
     return nullptr;
 }
 
-// style distance ==> [0,500]
-static inline double
-StyleDistance(const gfxFontEntry* aFontEntry, FontSlantStyle aTargetStyle)
-{
-    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;
-    }
+#define STYLE_SHIFT 2 // number of bits to contain style distance
 
-    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;
+// style distance ==> [0,2]
+static inline uint32_t
+StyleDistance(FontSlantStyle aFontStyle, FontSlantStyle aTargetStyle)
+{
+    if (aFontStyle == aTargetStyle) {
+        return 0; // styles match exactly ==> 0
     }
-
-    double distance = 0.0;
-    if (target < minAngle || target > maxAngle) {
-        if (target > 0.0) {
-            distance = minAngle - target;
-        } else {
-            distance = target - maxAngle;
-        }
+    if (aFontStyle == FontSlantStyle::Normal() ||
+        aTargetStyle == FontSlantStyle::Normal()) {
+        return 2; // one is normal (but not the other) ==> 2
     }
-    if (distance < 0.0) {
-        distance = kReverseDistance - distance;
-    }
-
-    return distance + extraDistance;
+    return 1; // neither is normal; must be italic vs oblique ==> 1
 }
 
-// stretch distance ==> [0,2000]
-static inline double
-StretchDistance(const gfxFontEntry* aFontEntry, FontStretch aTargetStretch)
+#define REVERSE_STRETCH_DISTANCE 200.0f
+
+// stretch distance ==> [0,350]
+static inline uint32_t
+StretchDistance(FontStretch aFontStretch, FontStretch aTargetStretch)
 {
-    const double kReverseDistance = 1000.0;
-    double distance = 0.0;
-
-    FontStretch minStretch = aFontEntry->Stretch().Min();
-    FontStretch maxStretch = aFontEntry->Stretch().Max();
-
-    if (aTargetStretch < minStretch || aTargetStretch > maxStretch) {
-        // stretch values are in the range 0 .. 1000
+    float distance = 0.0f;
+    if (aTargetStretch != aFontStretch) {
+        // stretch values are in the range 50 .. 200
         // if aTargetStretch is >100, we prefer larger values;
         // if <=100, prefer smaller
         if (aTargetStretch > FontStretch::Normal()) {
-            distance = (minStretch - aTargetStretch);
+            distance = (aFontStretch - aTargetStretch);
         } else {
-            distance = (aTargetStretch - maxStretch);
+            distance = (aTargetStretch - aFontStretch);
         }
         // 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 1000) by adding an extra 1000 to the absolute value
+        // (max possible is 150) by adding an extra 200 to the absolute value
         if (distance < 0.0f) {
-            distance = kReverseDistance - distance;
+            distance = -distance + REVERSE_STRETCH_DISTANCE;
         }
     }
-    return distance;
+    return uint32_t(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.
 
-// weight distance ==> [0,1600]
-static inline double
-WeightDistance(const gfxFontEntry* aFontEntry, FontWeight aTargetWeight)
-{
-    const double kReverseDistance = 600.0;
+#define REVERSE_WEIGHT_DISTANCE 600
+#define WEIGHT_SHIFT             11 // number of bits to contain weight distance
 
-    double distance = 0.0, addedDistance = 0.0;
-    FontWeight minWeight = aFontEntry->Weight().Min();
-    FontWeight maxWeight = aFontEntry->Weight().Max();
-    if (aTargetWeight < minWeight || aTargetWeight > maxWeight) {
+// weight distance ==> [0,1598]
+static inline uint32_t
+WeightDistance(FontWeight aFontWeight, FontWeight aTargetWeight)
+{
+    // Compute a measure of the "distance" between the requested
+    // weight and the given fontEntry
+
+    float distance = 0.0f, addedDistance = 0.0f;
+    if (aTargetWeight != aFontWeight) {
         if (aTargetWeight > FontWeight(500)) {
-            distance = minWeight - aTargetWeight;
+            distance = aFontWeight - aTargetWeight;
         } else if (aTargetWeight < FontWeight(400)) {
-            distance = aTargetWeight - maxWeight;
+            distance = aTargetWeight - aFontWeight;
         } else {
             // special case - target is between 400 and 500
 
             // font weights between 400 and 500 are close
-            if (maxWeight >= FontWeight(400) &&
-                minWeight <= FontWeight(500)) {
-                if (maxWeight < aTargetWeight) {
-                    distance = FontWeight(500) - maxWeight;
+            if (aFontWeight >= FontWeight(400) &&
+                aFontWeight <= FontWeight(500)) {
+                if (aFontWeight < aTargetWeight) {
+                    distance = FontWeight(500) - aFontWeight;
                 } else {
-                    distance = minWeight - aTargetWeight;
+                    distance = aFontWeight - 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.0;
+                distance = aTargetWeight - aFontWeight;
+                addedDistance = 100;
             }
         }
-        if (distance < 0.0) {
-            distance = kReverseDistance - distance;
+        if (distance < 0.0f) {
+            distance = -distance + REVERSE_WEIGHT_DISTANCE;
         }
         distance += addedDistance;
     }
-    return distance;
+    return uint32_t(distance);
 }
 
-#define MAX_DISTANCE 1.0e20 // >> than any WeightStyleStretchDistance result
+#define MAX_DISTANCE 0xffffffff
 
-static inline double
+static inline uint32_t
 WeightStyleStretchDistance(gfxFontEntry* aFontEntry,
                            const gfxFontStyle& aTargetStyle)
 {
-    double stretchDist = StretchDistance(aFontEntry, aTargetStyle.stretch);
-    double styleDist = StyleDistance(aFontEntry, aTargetStyle.style);
-    double weightDist = WeightDistance(aFontEntry, aTargetStyle.weight);
+    // 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->Weight(), aTargetStyle.weight);
 
-    // 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);
+    NS_ASSERTION(weightDist < (1 << WEIGHT_SHIFT), "weight value out of bounds");
+    NS_ASSERTION(styleDist < (1 << STYLE_SHIFT), "slope value out of bounds");
 
-    // 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;
+    return (stretchDist << (STYLE_SHIFT + WEIGHT_SHIFT)) |
+           (styleDist << WEIGHT_SHIFT) |
+           weightDist;
 }
 
 void
 gfxFontFamily::FindAllFontsForStyle(const gfxFontStyle& aFontStyle,
                                     nsTArray<gfxFontEntry*>& aFontEntryList,
                                     bool& aNeedsSyntheticBold,
                                     bool aIgnoreSizeTolerance)
 {
@@ -1543,24 +1382,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.
 
-    double minDistance = MAX_DISTANCE;
+    uint32_t 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
-        double distance = WeightStyleStretchDistance(fe, aFontStyle);
+        uint32_t distance = WeightStyleStretchDistance(fe, aFontStyle);
         if (distance < minDistance) {
             matched = fe;
             if (!aFontEntryList.IsEmpty()) {
                 aFontEntryList.Clear();
             }
             minDistance = distance;
         } else if (distance == minDistance) {
             if (matched) {
@@ -1595,33 +1434,27 @@ gfxFontFamily::CheckForSimpleFamily()
                 // if none then the family is unusable anyway
     }
 
     if (count == 1) {
         mIsSimpleFamily = true;
         return;
     }
 
-    StretchRange firstStretch = mAvailableFonts[0]->Stretch();
-    if (!firstStretch.IsSingle()) {
-        return; // family with variation fonts is not considered "simple"
-    }
+    FontStretch firstStretch = mAvailableFonts[0]->Stretch();
 
     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().IsSingle() || !fe->SlantStyle().IsSingle()) {
-            return; // family with variation fonts is not considered "simple"
-        }
         uint8_t faceIndex = (fe->IsItalic() ? kItalicMask : 0) |
-                            (fe->IsBold() ? kBoldMask : 0);
+                            (fe->Weight() >= FontWeight(600) ? kBoldMask : 0);
         if (faces[faceIndex]) {
             return; // two faces resolve to the same slot; family isn't "simple"
         }
         faces[faceIndex] = fe;
     }
 
     // we have successfully slotted the available faces into the standard
     // 4-face framework
@@ -1658,51 +1491,43 @@ gfxFontFamily::ContainsFace(gfxFontEntry
 
 void gfxFontFamily::LocalizedName(nsAString& aLocalizedName)
 {
     // just return the primary name; subclasses should override
     aLocalizedName = mName;
 }
 
 // metric for how close a given font matches a style
-static float
+static int32_t
 CalcStyleMatch(gfxFontEntry *aFontEntry, const gfxFontStyle *aStyle)
 {
-    float rank = 0;
+    int32_t rank = 0;
     if (aStyle) {
-        // TODO: stretch
-
-        // italics
-        bool wantUpright = aStyle->style.IsNormal();
-        if (aFontEntry->IsUpright() == wantUpright) {
-            rank += 5000.0f;
-        }
+         // italics
+         bool wantUpright = aStyle->style.IsNormal();
+         if (aFontEntry->IsUpright() == wantUpright) {
+             rank += 10;
+         }
 
         // measure of closeness of weight to the desired value
-        if (aFontEntry->Weight().Min() > aStyle->weight) {
-            rank += aFontEntry->Weight().Min() - aStyle->weight;
-        } else if (aFontEntry->Weight().Max() < aStyle->weight) {
-            rank += aStyle->weight - aFontEntry->Weight().Max();
-        } else {
-            rank += 2000.0f; // the font supports the exact weight wanted
-        }
+        rank += 9 - Abs((aFontEntry->Weight() - aStyle->weight) / 100.0f);
     } else {
         // if no font to match, prefer non-bold, non-italic fonts
         if (aFontEntry->IsUpright()) {
-            rank += 2000.0f;
+            rank += 3;
         }
         if (!aFontEntry->IsBold()) {
-            rank += 1000.0f;
+            rank += 2;
         }
     }
 
     return rank;
 }
 
-#define RANK_MATCHED_CMAP   10000.0f
+#define RANK_MATCHED_CMAP   20
 
 void
 gfxFontFamily::FindFontForChar(GlobalFontMatch *aMatchData)
 {
     if (mFamilyCharacterMapInitialized && !TestCharacterMap(aMatchData->mCh)) {
         // none of the faces in the family support the required char,
         // so bail out immediately
         return;
@@ -1710,17 +1535,17 @@ gfxFontFamily::FindFontForChar(GlobalFon
 
     bool needsBold;
     gfxFontEntry *fe =
         FindFontForStyle(aMatchData->mStyle ? *aMatchData->mStyle
                                             : gfxFontStyle(),
                          needsBold, true);
 
     if (fe && !fe->SkipDuringSystemFallback()) {
-        float rank = 0;
+        int32_t rank = 0;
 
         if (fe->HasCharacter(aMatchData->mCh)) {
             rank += RANK_MATCHED_CMAP;
             aMatchData->mCount++;
 
             LogModule* log = gfxPlatform::GetLog(eGfxLog_textrun);
 
             if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Debug))) {
@@ -1770,17 +1595,17 @@ gfxFontFamily::FindFontForChar(GlobalFon
 
 void
 gfxFontFamily::SearchAllFontsForChar(GlobalFontMatch *aMatchData)
 {
     uint32_t i, numFonts = mAvailableFonts.Length();
     for (i = 0; i < numFonts; i++) {
         gfxFontEntry *fe = mAvailableFonts[i];
         if (fe && fe->HasCharacter(aMatchData->mCh)) {
-            float rank = RANK_MATCHED_CMAP;
+            int32_t rank = RANK_MATCHED_CMAP;
             rank += CalcStyleMatch(fe, aMatchData->mStyle);
             if (rank > aMatchData->mMatchRank
                 || (rank == aMatchData->mMatchRank &&
                     Compare(fe->Name(), aMatchData->mBestMatch->Name()) > 0))
             {
                 aMatchData->mBestMatch = fe;
                 aMatchData->mMatchedFamily = this;
                 aMatchData->mMatchRank = rank;
--- a/gfx/thebes/gfxFontEntry.h
+++ b/gfx/thebes/gfxFontEntry.h
@@ -110,19 +110,16 @@ 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).
@@ -141,43 +138,40 @@ public:
     // will (usually, except on Linux) load and parse the 'name' table;
     // 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; }
-    StretchRange Stretch() const { return mStretchRange; }
-    SlantStyleRange SlantStyle() const { return mStyleRange; }
+    FontWeight Weight() const { return mWeight; }
+    FontStretch Stretch() const { return mStretch; }
 
     bool IsUserFont() const { return mIsDataUserFont || mIsLocalUserFont; }
     bool IsLocalUserFont() const { return mIsLocalUserFont; }
     bool IsFixedPitch() const { return mFixedPitch; }
-    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 IsItalic() const { return mStyle.IsItalic(); }
+    bool IsOblique() const { return mStyle.IsOblique(); }
+    bool IsUpright() const { return mStyle.IsNormal(); }
+    bool IsBold() const { return mWeight.IsBold(); } // bold == weights 600 and above
     bool IgnoreGDEF() const { return mIgnoreGDEF; }
     bool IgnoreGSUB() const { return mIgnoreGSUB; }
 
     // Return whether the face corresponds to "normal" CSS style properties:
     //    font-style: normal;
     //    font-weight: normal;
     //    font-stretch: normal;
     // If this is false, we might want to fall back to a different face and
     // possibly apply synthetic styling.
     bool IsNormalStyle() const
     {
         return IsUpright() &&
-               Weight().Min() <= FontWeight::Normal() &&
-               Weight().Max() >= FontWeight::Normal() &&
-               Stretch().Min() <= FontStretch::Normal() &&
-               Stretch().Max() >= FontStretch::Normal();
+               Weight() == FontWeight::Normal() &&
+               Stretch().IsNormal();
     }
 
     // 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
@@ -371,26 +365,16 @@ public:
     }
     virtual void GetVariationAxes(nsTArray<gfxFontVariationAxis>& aVariationAxes)
     {
     }
     virtual void GetVariationInstances(nsTArray<gfxFontVariationInstance>& aInstances)
     {
     }
 
-    // Set up the entry's weight/stretch/style ranges according to axes found
-    // by GetVariationAxes (for installed fonts; do NOT call this for user
-    // fonts, where the ranges are provided by @font-face descriptors).
-    void SetupVariationRanges();
-
-    // Get variation axis settings that should be used to implement a particular
-    // font style using this resource.
-    void GetVariationsForStyle(nsTArray<gfxFontVariation>& aResult,
-                               const gfxFontStyle& aStyle);
-
     // Get the font's list of features (if any) for DevTools support.
     void GetFeatureInfo(nsTArray<gfxFontFeatureInfo>& aFeatureInfo);
 
     nsString         mName;
     nsString         mFamilyName;
 
     bool             mFixedPitch  : 1;
     bool             mIsBadUnderlineFont : 1;
@@ -416,19 +400,19 @@ public:
     bool             mGrFaceInitialized : 1;
     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;
-    StretchRange     mStretchRange;
-    SlantStyleRange  mStyleRange;
+    FontWeight mWeight;
+    FontStretch mStretch;
+    FontSlantStyle mStyle;
 
     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;
@@ -623,24 +607,24 @@ private:
 };
 
 
 // used when iterating over all fonts looking for a match for a given character
 struct GlobalFontMatch {
     GlobalFontMatch(const uint32_t aCharacter,
                     const gfxFontStyle *aStyle) :
         mCh(aCharacter), mStyle(aStyle),
-        mMatchRank(0.0f), mCount(0), mCmapsTested(0)
+        mMatchRank(0), mCount(0), mCmapsTested(0)
         {
 
         }
 
     const uint32_t         mCh;          // codepoint to be matched
     const gfxFontStyle*    mStyle;       // style to match
-    float                  mMatchRank;   // metric indicating closest match
+    int32_t                mMatchRank;   // metric indicating closest match
     RefPtr<gfxFontEntry> mBestMatch;   // current best match
     RefPtr<gfxFontFamily> mMatchedFamily; // the family it belongs to
     uint32_t               mCount;       // number of fonts matched
     uint32_t               mCmapsTested; // number of cmaps tested
 };
 
 class gfxFontFamily {
 public:
--- a/gfx/thebes/gfxFontUtils.cpp
+++ b/gfx/thebes/gfxFontUtils.cpp
@@ -1939,16 +1939,34 @@ gfxFontUtils::GetVariationInstances(gfxF
             value.mAxis = axes[j].axisTag;
             value.mValue = int32_t(coords[j]) / 65536.0;
             instance.mValues.AppendElement(value);
         }
         aInstances.AppendElement(instance);
     }
 }
 
+void
+gfxFontUtils::MergeVariations(const nsTArray<gfxFontVariation>& aEntrySettings,
+                              const nsTArray<gfxFontVariation>& aStyleSettings,
+                              nsTArray<gfxFontVariation>* aMerged)
+{
+    MOZ_ASSERT(!aEntrySettings.IsEmpty() &&
+               !aStyleSettings.IsEmpty() &&
+               aMerged->IsEmpty());
+    // Settings from the CSS style will take precedence over those from the
+    // font entry (i.e. from the @font-face descriptor).
+    aMerged->AppendElements(aStyleSettings);
+    for (auto& setting : aEntrySettings) {
+        if (!aMerged->Contains(setting.mTag, VariationTagComparator())) {
+            aMerged->AppendElement(setting);
+        }
+    }
+}
+
 #ifdef XP_WIN
 
 /* static */
 bool
 gfxFontUtils::IsCffFont(const uint8_t* aFontData)
 {
     // this is only called after aFontData has passed basic validation,
     // so we know there is enough data present to allow us to read the version!
--- a/gfx/thebes/gfxFontUtils.h
+++ b/gfx/thebes/gfxFontUtils.h
@@ -1005,16 +1005,32 @@ public:
     // platforms where the native font APIs don't provide the info we want
     // in a convenient form.
     // (Not used on platforms -- currently, freetype -- where the font APIs
     // expose variation instance details directly.)
     static void
     GetVariationInstances(gfxFontEntry* aFontEntry,
                           nsTArray<gfxFontVariationInstance>& aInstances);
 
+    // Merge a list of font-variation-settings from a font entry and a list
+    // from a gfxFontStyle, to get a combined collection of settings that can
+    // be used to instantiate a font.
+    static void
+    MergeVariations(const nsTArray<gfxFontVariation>& aEntrySettings,
+                    const nsTArray<gfxFontVariation>& aStyleSettings,
+                    nsTArray<gfxFontVariation>* aMerged);
+
+    // Helper used by MergeVariations, and other code that wants to check
+    // whether an array of variation settings includes a particular tag.
+    struct VariationTagComparator {
+        bool Equals(const gfxFontVariation& aVariation, uint32_t aTag) const {
+            return aVariation.mTag == aTag;
+        }
+    };
+
 protected:
     friend struct MacCharsetMappingComparator;
 
     static nsresult
     ReadNames(const char *aNameData, uint32_t aDataLen, uint32_t aNameID,
               int32_t aLangID, int32_t aPlatformID, nsTArray<nsString>& aNames);
 
     // convert opentype name-table platform/encoding/language values to an
--- a/gfx/thebes/gfxGDIFont.cpp
+++ b/gfx/thebes/gfxGDIFont.cpp
@@ -455,20 +455,17 @@ gfxGDIFont::FillLogFont(LOGFONTW& aLogFo
             // choice of actual face used (bug 724231)
             weight = 0;
         } else {
             // avoid GDI synthetic bold which occurs when weight
             // specified is >= font data weight + 200
             weight = mNeedsBold ? 700 : 200;
         }
     } else {
-        // GDI doesn't support variation fonts, so for system fonts we know
-        // that the entry has only a single weight, not a range.
-        MOZ_ASSERT(fe->Weight().IsSingle());
-        weight = mNeedsBold ? 700 : fe->Weight().Min().ToIntRounded();
+        weight = mNeedsBold ? 700 : fe->Weight().ToIntRounded();
     }
 
     fe->FillLogFont(&aLogFont, weight, aSize);
 }
 
 uint32_t
 gfxGDIFont::GetGlyph(uint32_t aUnicode, uint32_t aVarSelector)
 {
--- a/gfx/thebes/gfxGDIFontList.cpp
+++ b/gfx/thebes/gfxGDIFontList.cpp
@@ -110,42 +110,42 @@ FontTypeToOutPrecision(uint8_t fontType)
 /***************************************************************
  *
  * GDIFontEntry
  *
  */
 
 GDIFontEntry::GDIFontEntry(const nsAString& aFaceName,
                            gfxWindowsFontType aFontType,
-                           SlantStyleRange aStyle,
-                           WeightRange aWeight,
-                           StretchRange aStretch,
+                           FontSlantStyle aStyle,
+                           FontWeight aWeight,
+                           FontStretch aStretch,
                            gfxUserFontData *aUserFontData)
     : gfxFontEntry(aFaceName),
       mFontType(aFontType),
       mForceGDI(false),
       mUnicodeRanges()
 {
     mUserFontData.reset(aUserFontData);
-    mStyleRange = aStyle;
-    mWeightRange = aWeight;
-    mStretchRange = aStretch;
+    mStyle = aStyle;
+    mWeight = aWeight;
+    mStretch = aStretch;
     if (IsType1())
         mForceGDI = true;
     mIsDataUserFont = aUserFontData != nullptr;
 
     InitLogFont(aFaceName, aFontType);
 }
 
 gfxFontEntry*
 GDIFontEntry::Clone() const
 {
     MOZ_ASSERT(!IsUserFont(), "we can only clone installed fonts!");
-    return new GDIFontEntry(Name(), mFontType, SlantStyle(), Weight(),
-                            Stretch(), nullptr);
+    return new GDIFontEntry(Name(), mFontType, mStyle, mWeight, mStretch,
+                            nullptr);
 }
 
 nsresult
 GDIFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
 {
     AUTO_PROFILER_LABEL("GDIFontEntry::ReadCMAP", OTHER);
 
     // attempt this once, if errors occur leave a blank cmap
@@ -300,17 +300,17 @@ GDIFontEntry::TestCharacterMap(uint32_t 
         if (aCh > 0xFFFF)
             return false;
 
         // previous code was using the group style
         gfxFontStyle fakeStyle;
         if (!IsUpright()) {
             fakeStyle.style = FontSlantStyle::Italic();
         }
-        fakeStyle.weight = Weight().Min();
+        fakeStyle.weight = mWeight;
 
         RefPtr<gfxFont> tempFont = FindOrMakeFont(&fakeStyle, false);
         if (!tempFont || !tempFont->Valid())
             return false;
         gfxGDIFont *font = static_cast<gfxGDIFont*>(tempFont.get());
 
         HDC dc = GetDC((HWND)nullptr);
         SetGraphicsMode(dc, GM_ADVANCED);
@@ -379,29 +379,29 @@ GDIFontEntry::InitLogFont(const nsAStrin
     mLogFont.lfClipPrecision  = CLIP_TURNOFF_FONTASSOCIATION;
     mLogFont.lfQuality        = DEFAULT_QUALITY;
     mLogFont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
     // always force lfItalic if we want it.  Font selection code will
     // do its best to give us an italic font entry, but if no face exists
     // it may give us a regular one based on weight.  Windows should
     // do fake italic for us in that case.
     mLogFont.lfItalic         = !IsUpright();
-    mLogFont.lfWeight         = Weight().Min().ToIntRounded();
+    mLogFont.lfWeight         = int(mWeight.ToFloat());
 
     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,
-                              SlantStyleRange aStyle,
-                              WeightRange aWeight,
-                              StretchRange aStretch,
+                              FontSlantStyle aStyle,
+                              FontWeight aWeight,
+                              FontStretch aStretch,
                               gfxUserFontData* aUserFontData)
 {
     // jtdfix - need to set charset, unicode ranges, pitch/family
 
     GDIFontEntry *fe = new GDIFontEntry(aName, aFontType, aStyle,
                                         aWeight, aStretch, aUserFontData);
 
     return fe;
@@ -462,35 +462,35 @@ GDIFontFamily::FamilyAddStylesProc(const
             // otherwise if the new type is worse, skip it
             return 1;
         }
     }
 
     for (uint32_t i = 0; i < ff->mAvailableFonts.Length(); ++i) {
         fe = static_cast<GDIFontEntry*>(ff->mAvailableFonts[i].get());
         // check if we already know about this face
-        if (fe->Weight().Min() == FontWeight(int32_t(logFont.lfWeight)) &&
+        if (fe->mWeight == FontWeight(int32_t(logFont.lfWeight)) &&
             fe->IsItalic() == (logFont.lfItalic == 0xFF)) {
             // update the charset bit here since this could be different
             // XXX Can we still do this now that we store mCharset
             // on the font family rather than the font entry?
             ff->mCharset.set(metrics.tmCharSet);
             return 1; 
         }
     }
 
     // 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, SlantStyleRange(italicStyle),
-                                       WeightRange(FontWeight(int32_t(logFont.lfWeight))),
-                                       StretchRange(FontStretch::Normal()),
+                                       feType, italicStyle,
+                                       FontWeight(int32_t(logFont.lfWeight)),
+                                       FontStretch::Normal(),
                                        nullptr);
     if (!fe)
         return 1;
 
     ff->AddFontEntry(fe);
 
     if (nmetrics->ntmFontSig.fsUsb[0] != 0x00000000 &&
         nmetrics->ntmFontSig.fsUsb[1] != 0x00000000 &&
@@ -503,22 +503,25 @@ 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: normal",
+             " with style: %s weight: %d stretch: %g%%",
              NS_ConvertUTF16toUTF8(fe->Name()).get(),
              NS_ConvertUTF16toUTF8(ff->Name()).get(),
              (logFont.lfItalic == 0xff) ? "italic" : "normal",
-             logFont.lfWeight));
+             logFont.lfWeight,
+             fe->Stretch().Percentage(),
+             stretchString.get()));
     }
     return 1;
 }
 
 void
 GDIFontFamily::FindStyleVariations(FontInfoData *aFontInfoData)
 {
     if (mHasStyles)
@@ -706,46 +709,45 @@ gfxGDIFontList::EnumFontFamExProc(ENUMLO
         family->mCharset.set(metrics.tmCharSet);
     }
 
     return 1;
 }
 
 gfxFontEntry* 
 gfxGDIFontList::LookupLocalFont(const nsAString& aFontName,
-                                WeightRange aWeightForEntry,
-                                StretchRange aStretchForEntry,
-                                SlantStyleRange aStyleForEntry)
+                                FontWeight aWeight,
+                                FontStretch aStretch,
+                                FontSlantStyle aStyle)
 {
     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->SlantStyle(), lookup->Weight(), aStretchForEntry, nullptr);
+        lookup->mStyle, lookup->mWeight, aStretch, nullptr);
 
     if (!fe)
         return nullptr;
 
     fe->mIsLocalUserFont = true;
 
     // make the new font entry match the userfont entry style characteristics
-    fe->mWeightRange = aWeightForEntry;
-    fe->mStyleRange = aStyleForEntry;
-    fe->mStretchRange = aStretchForEntry;
+    fe->mWeight = aWeight;
+    fe->mStyle = aStyle;
 
     return fe;
 }
 
 // If aFontData contains only a MS/Symbol cmap subtable, not MS/Unicode,
 // we modify the subtable header to mark it as Unicode instead, because
 // otherwise GDI will refuse to load the font.
 // NOTE that this function does not bounds-check every access to the font data.
@@ -799,19 +801,19 @@ FixupSymbolEncodedFont(uint8_t* aFontDat
             return true;
         }
     }
     return false;
 }
 
 gfxFontEntry*
 gfxGDIFontList::MakePlatformFont(const nsAString& aFontName,
-                                 WeightRange aWeightForEntry,
-                                 StretchRange aStretchForEntry,
-                                 SlantStyleRange aStyleForEntry,
+                                 FontWeight aWeight,
+                                 FontStretch aStretch,
+                                 FontSlantStyle aStyle,
                                  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)
@@ -866,17 +868,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*/,
-        aStyleForEntry, aWeightForEntry, aStretchForEntry, winUserFontData);
+        aStyle, aWeight, aStretch, winUserFontData);
 
     if (fe) {
       fe->mIsDataUserFont = true;
     }
 
     return fe;
 }
 
--- a/gfx/thebes/gfxGDIFontList.h
+++ b/gfx/thebes/gfxGDIFontList.h
@@ -103,16 +103,20 @@ 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);
 
@@ -161,31 +165,37 @@ 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,
-                                         SlantStyleRange aStyle,
-                                         WeightRange aWeight,
-                                         StretchRange aStretch,
+                                         FontSlantStyle aStyle,
+                                         FontWeight aWeight,
+                                         FontStretch 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,
-                 SlantStyleRange aStyle, WeightRange aWeight, StretchRange aStretch,
+                 FontSlantStyle aStyle, FontWeight aWeight, FontStretch 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,
@@ -307,40 +317,44 @@ 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,
-                                          WeightRange aWeightForEntry,
-                                          StretchRange aStretchForEntry,
-                                          SlantStyleRange aStyleForEntry);
+                                          FontWeight aWeight,
+                                          FontStretch aStretch,
+                                          FontSlantStyle aStyle);
 
     virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
-                                           WeightRange aWeightForEntry,
-                                           StretchRange aStretchForEntry,
-                                           SlantStyleRange aStyleForEntry,
+                                           FontWeight aWeight,
+                                           FontStretch aStretch,
+                                           FontSlantStyle aStyle,
                                            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,32 +31,44 @@ gfxMacFont::gfxMacFont(const RefPtr<Unsc
       mCGFont(nullptr),
       mCTFont(nullptr),
       mFontFace(nullptr),
       mFontSmoothingBackgroundColor(aFontStyle->fontSmoothingBackgroundColor),
       mVariationFont(aFontEntry->HasVariations())
 {
     mApplySyntheticBold = aNeedsBold;
 
-    if (mVariationFont) {
+    if (mVariationFont && (!aFontStyle->variationSettings.IsEmpty() ||
+                           !aFontEntry->mVariationSettings.IsEmpty())) {
         CGFontRef baseFont = aUnscaledFont->GetFont();
         if (!baseFont) {
             mIsValid = false;
             return;
         }
 
-        // Get the variation settings needed to instantiate the fontEntry
-        // for a particular fontStyle.
-        AutoTArray<gfxFontVariation,4> vars;
-        aFontEntry->GetVariationsForStyle(vars, *aFontStyle);
+        // Probably one of the lists of variations, either from the @font-face
+        // descriptor or from the property, will be empty. So skip merging them
+        // unless really necessary.
+        const nsTArray<gfxFontVariation>* vars;
+        AutoTArray<gfxFontVariation,4> mergedSettings;
+        if (aFontStyle->variationSettings.IsEmpty()) {
+            vars = &aFontEntry->mVariationSettings;
+        } else if (aFontEntry->mVariationSettings.IsEmpty()) {
+            vars = &aFontStyle->variationSettings;
+        } else {
+            gfxFontUtils::MergeVariations(aFontEntry->mVariationSettings,
+                                          aFontStyle->variationSettings,
+                                          &mergedSettings);
+            vars = &mergedSettings;
+        }
 
         mCGFont =
             UnscaledFontMac::CreateCGFontWithVariations(baseFont,
-                                                        vars.Length(),
-                                                        vars.Elements());
+                                                        vars->Length(),
+                                                        vars->Elements());
         if (!mCGFont) {
           ::CFRetain(baseFont);
           mCGFont = baseFont;
         }
     } else {
         mCGFont = aUnscaledFont->GetFont();
         if (!mCGFont) {
             mIsValid = false;
--- 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, WeightRange aWeight,
+    MacOSFontEntry(const nsAString& aPostscriptName, FontWeight aWeight,
                    bool aIsStandardFace = false,
                    double aSizeHint = 0.0);
 
     // for use with data fonts
     MacOSFontEntry(const nsAString& aPostscriptName, CGFontRef aFontRef,
-                   WeightRange aWeight, StretchRange aStretch, SlantStyleRange aStyle,
+                   FontWeight aWeight, FontStretch aStretch, FontSlantStyle 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,
-                                  WeightRange aWeightForEntry,
-                                  StretchRange aStretchForEntry,
-                                  SlantStyleRange aStyleForEntry) override;
+                                  FontWeight aWeight,
+                                  FontStretch aStretch,
+                                  FontSlantStyle aStyle) override;
 
     gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
-                                   WeightRange aWeightForEntry,
-                                   StretchRange aStretchForEntry,
-                                   SlantStyleRange aStyleForEntry,
+                                   FontWeight aWeight,
+                                   FontStretch aStretch,
+                                   FontSlantStyle aStyle,
                                    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,
-                               WeightRange aWeight,
+                               FontWeight 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 = aWeight;
+    mWeight = aWeight;
 }
 
 MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
                                CGFontRef aFontRef,
-                               WeightRange aWeight,
-                               StretchRange aStretch,
-                               SlantStyleRange aStyle,
+                               FontWeight aWeight,
+                               FontStretch aStretch,
+                               FontSlantStyle aStyle,
                                bool aIsDataUserFont,
                                bool aIsLocalUserFont)
     : gfxFontEntry(aPostscriptName, false),
       mFontRef(NULL),
       mSizeHint(0.0),
       mFontRefInitialized(false),
       mRequiresAAT(false),
       mIsCFF(false),
@@ -408,35 +408,35 @@ MacOSFontEntry::MacOSFontEntry(const nsA
       mTrakTable(nullptr),
       mTrakValues(nullptr),
       mTrakSizeTable(nullptr)
 {
     mFontRef = aFontRef;
     mFontRefInitialized = true;
     ::CFRetain(mFontRef);
 
-    mWeightRange = aWeight;
-    mStretchRange = aStretch;
+    mWeight = aWeight;
+    mStretch = aStretch;
     mFixedPitch = false; // xxx - do we need this for downloaded fonts?
-    mStyleRange = aStyle;
+    mStyle = 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(), mStandardFace, mSizeHint);
-    fe->mStyleRange = mStyleRange;
-    fe->mStretchRange = mStretchRange;
+        new MacOSFontEntry(Name(), mWeight, mStandardFace, mSizeHint);
+    fe->mStyle = mStyle;
+    fe->mStretch = mStretch;
     fe->mFixedPitch = mFixedPitch;
     return fe;
 }
 
 CGFontRef
 MacOSFontEntry::GetFontRef()
 {
     if (!mFontRefInitialized) {
@@ -899,56 +899,48 @@ gfxMacFontFamily::FindStyleVariations(Fo
             [facename isEqualToString:@"Bold Italic"] ||
             [facename isEqualToString:@"Bold Oblique"])
         {
             isStandardFace = true;
         }
 
         // create a font entry
         MacOSFontEntry *fontEntry =
-            new MacOSFontEntry(postscriptFontName,
-                               WeightRange(FontWeight(cssWeight)),
+            new MacOSFontEntry(postscriptFontName, FontWeight(cssWeight),
                                isStandardFace, mSizeHint);
         if (!fontEntry) {
             break;
         }
 
         // set additional properties based on the traits reported by Cocoa
         if (macTraits & (NSCondensedFontMask | NSNarrowFontMask | NSCompressedFontMask)) {
-            fontEntry->mStretchRange = StretchRange(FontStretch::Condensed());
+            fontEntry->mStretch = FontStretch::Condensed();
         } else if (macTraits & NSExpandedFontMask) {
-            fontEntry->mStretchRange = StretchRange(FontStretch::Expanded());
+            fontEntry->mStretch = 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->mStyleRange = SlantStyleRange(FontSlantStyle::Italic());
+            fontEntry->mStyle = 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: %s"
+                 " with style: %s weight: %d stretch: %g%%"
                  " (apple-weight: %d macTraits: %8.8x)",
                  NS_ConvertUTF16toUTF8(fontEntry->Name()).get(),
                  NS_ConvertUTF16toUTF8(Name()).get(),
                  fontEntry->IsItalic() ? "italic" : "normal",
-                 weightString.get(),
-                 stretchString.get(),
+                 cssWeight, fontEntry->Stretch().Percentage(),
                  appKitWeight, macTraits));
         }
 
         // insert into font entry array of family
         AddFontEntry(fontEntry);
     }
 
     SortAvailableFonts();
@@ -1285,17 +1277,17 @@ 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(), true,
+                new MacOSFontEntry(fe->Name(), fe->mWeight, true,
                                    static_cast<const MacOSFontEntry*>(fe)->
                                        mSizeHint);
             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()));
@@ -1536,55 +1528,60 @@ gfxMacPlatformFontList::AppleWeightToCSS
         aAppleWeight = 1;
     else if (aAppleWeight > kAppleMaxWeight)
         aAppleWeight = kAppleMaxWeight;
     return gAppleWeightToCSSWeight[aAppleWeight];
 }
 
 gfxFontEntry*
 gfxMacPlatformFontList::LookupLocalFont(const nsAString& aFontName,
-                                        WeightRange aWeightForEntry,
-                                        StretchRange aStretchForEntry,
-                                        SlantStyleRange aStyleForEntry)
+                                        FontWeight aWeight,
+                                        FontStretch aStretch,
+                                        FontSlantStyle aStyle)
 {
     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, aWeightForEntry,
-                           aStretchForEntry, aStyleForEntry,
+        new MacOSFontEntry(aFontName, fontRef, aWeight, aStretch, aStyle,
                            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,
-                                         WeightRange aWeightForEntry,
-                                         StretchRange aStretchForEntry,
-                                         SlantStyleRange aStyleForEntry,
+                                         FontWeight aWeight,
+                                         FontStretch aStretch,
+                                         FontSlantStyle aStyle,
                                          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;
     }
 
@@ -1594,19 +1591,18 @@ gfxMacPlatformFontList::MakePlatformFont
     CGFontRef fontRef = ::CGFontCreateWithDataProvider(provider);
     ::CGDataProviderRelease(provider);
 
     if (!fontRef) {
         return nullptr;
     }
 
     auto newFontEntry =
-        MakeUnique<MacOSFontEntry>(uniqueName, fontRef, aWeightForEntry,
-                                   aStretchForEntry, aStyleForEntry,
-                                   true, false);
+        MakeUnique<MacOSFontEntry>(uniqueName, fontRef, aWeight, aStretch,
+                                   aStyle, 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
@@ -769,20 +769,16 @@ gfxPlatform::Init()
 #  endif
 #endif
 
     InitLayersIPC();
 
     gPlatform->PopulateScreenInfo();
     gPlatform->ComputeTileSize();
 
-#ifdef MOZ_ENABLE_FREETYPE
-    Factory::SetFTLibrary(gPlatform->GetFTLibrary());
-#endif
-
     nsresult rv;
     rv = gfxPlatformFontList::Init();
     if (NS_FAILED(rv)) {
         MOZ_CRASH("Could not initialize gfxPlatformFontList");
     }
 
     gPlatform->mScreenReferenceSurface =
         gPlatform->CreateOffscreenSurface(IntSize(1, 1),
@@ -804,16 +800,20 @@ gfxPlatform::Init()
       }
     }
 
     rv = gfxFontCache::Init();
     if (NS_FAILED(rv)) {
         MOZ_CRASH("Could not initialize gfxFontCache");
     }
 
+#ifdef MOZ_ENABLE_FREETYPE
+    Factory::SetFTLibrary(gPlatform->GetFTLibrary());
+#endif
+
     /* Create and register our CMS Override observer. */
     gPlatform->mSRGBOverrideObserver = new SRGBOverrideObserver();
     Preferences::AddWeakObserver(gPlatform->mSRGBOverrideObserver, GFX_PREF_CMS_FORCE_SRGB);
 
     gPlatform->mFontPrefsObserver = new FontPrefsObserver();
     Preferences::AddStrongObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
 
     GLContext::PlatformStartup();
@@ -1740,36 +1740,40 @@ gfxPlatform::IsFontFormatSupported(uint3
     }
 
     // no format hint set, need to look at data
     return true;
 }
 
 gfxFontEntry*
 gfxPlatform::LookupLocalFont(const nsAString& aFontName,
-                             WeightRange aWeightForEntry,
-                             StretchRange aStretchForEntry,
-                             SlantStyleRange aStyleForEntry)
+                             FontWeight aWeight,
+                             FontStretch aStretch,
+                             FontSlantStyle aStyle)
 {
-    return gfxPlatformFontList::PlatformFontList()->
-        LookupLocalFont(aFontName, aWeightForEntry, aStretchForEntry,
-                        aStyleForEntry);
+    return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aFontName,
+                                                                    aWeight,
+                                                                    aStretch,
+                                                                    aStyle);
 }
 
 gfxFontEntry*
 gfxPlatform::MakePlatformFont(const nsAString& aFontName,
-                              WeightRange aWeightForEntry,
-                              StretchRange aStretchForEntry,
-                              SlantStyleRange aStyleForEntry,
+                              FontWeight aWeight,
+                              FontStretch aStretch,
+                              FontSlantStyle aStyle,
                               const uint8_t* aFontData,
                               uint32_t aLength)
 {
-    return gfxPlatformFontList::PlatformFontList()->
-        MakePlatformFont(aFontName, aWeightForEntry, aStretchForEntry,
-                         aStyleForEntry, aFontData, aLength);
+    return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aFontName,
+                                                                     aWeight,
+                                                                     aStretch,
+                                                                     aStyle,
+                                                                     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::StretchRange StretchRange;
-    typedef mozilla::SlantStyleRange SlantStyleRange;
-    typedef mozilla::WeightRange WeightRange;
+    typedef mozilla::FontStretch FontStretch;
+    typedef mozilla::FontSlantStyle FontSlantStyle;
+    typedef mozilla::FontWeight FontWeight;
     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.
      */
-    gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
-                                  WeightRange aWeightForEntry,
-                                  StretchRange aStretchForEntry,
-                                  SlantStyleRange aStyleForEntry);
+    virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
+                                          FontWeight aWeight,
+                                          FontStretch aStretch,
+                                          FontSlantStyle aStyle);
 
     /**
      * 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.
      */
-    gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
-                                   WeightRange aWeightForEntry,
-                                   StretchRange aStretchForEntry,
-                                   SlantStyleRange aStyleForEntry,
-                                   const uint8_t* aFontData,
-                                   uint32_t aLength);
+    virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
+                                           FontWeight aWeight,
+                                           FontStretch aStretch,
+                                           FontSlantStyle aStyle,
+                                           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::StretchRange StretchRange;
-    typedef mozilla::SlantStyleRange SlantStyleRange;
-    typedef mozilla::WeightRange WeightRange;
+    typedef mozilla::FontStretch FontStretch;
+    typedef mozilla::FontSlantStyle FontSlantStyle;
+    typedef mozilla::FontWeight FontWeight;
     typedef mozilla::unicode::Script Script;
 
     static gfxPlatformFontList* PlatformFontList() {
         return sPlatformFontList;
     }
 
     static nsresult Init() {
         NS_ASSERTION(!sPlatformFontList, "What's this doing here?");
@@ -183,43 +183,28 @@ 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.
-     *
-     * 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.
-     */
+    // look up a font by name on the host platform
     virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
-                                          WeightRange aWeightForEntry,
-                                          StretchRange aStretchForEntry,
-                                          SlantStyleRange aStyleForEntry) = 0;
+                                          FontWeight aWeight,
+                                          FontStretch aStretch,
+                                          FontSlantStyle aStyle) = 0;
 
-    /**
-     * 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.
-     */
+    // create a new platform font from downloaded data (@font-face)
+    // this method is responsible to ensure aFontData is free()'d
     virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
-                                           WeightRange aWeightForEntry,
-                                           StretchRange aStretchForEntry,
-                                           SlantStyleRange aStyleForEntry,
+                                           FontWeight aWeight,
+                                           FontStretch aStretch,
+                                           FontSlantStyle aStyle,
                                            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,16 +268,40 @@ 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,16 +57,36 @@ 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,66 +100,68 @@ private:
     void*        mPtr;
     size_t       mLength;
     const size_t mLimit;
     off_t        mOff;
 };
 
 gfxUserFontEntry::gfxUserFontEntry(gfxUserFontSet* aFontSet,
              const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
-             WeightRange aWeight,
-             StretchRange aStretch,
-             SlantStyleRange aStyle,
+             FontWeight aWeight,
+             FontStretch aStretch,
+             FontSlantStyle 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 = aWeight;
-    mStretchRange = aStretch;
-    mStyleRange = aStyle;
+    mWeight = aWeight;
+    mStretch = aStretch;
+    mStyle = 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,
-                          WeightRange aWeight,
-                          StretchRange aStretch,
-                          SlantStyleRange aStyle,
+                          FontWeight aWeight,
+                          FontStretch aStretch,
+                          FontSlantStyle aStyle,
                           const nsTArray<gfxFontFeature>& aFeatureSettings,
                           const nsTArray<gfxFontVariation>& aVariationSettings,
                           uint32_t aLanguageOverride,
                           gfxCharacterMap* aUnicodeRanges,
                           uint8_t aFontDisplay)
 {
-    return Weight() == aWeight &&
-           Stretch() == aStretch &&
-           SlantStyle() == aStyle &&
+    return mWeight == aWeight &&
+           mStretch == aStretch &&
+           mStyle == aStyle &&
            mFeatureSettings == aFeatureSettings &&
            mVariationSettings == aVariationSettings &&
            mLanguageOverride == aLanguageOverride &&
            mSrcList == aFontFaceSrcList &&
            mFontDisplay == aFontDisplay &&
            ((!aUnicodeRanges && !mCharacterMap) ||
             (aUnicodeRanges && mCharacterMap && mCharacterMap->Equals(aUnicodeRanges)));
 }
@@ -509,19 +511,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(),
-                                                            Stretch(),
-                                                            SlantStyle());
+                                                            mWeight,
+                                                            mStretch,
+                                                            mStyle);
             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) {
@@ -764,19 +766,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(),
-                                                          Stretch(),
-                                                          SlantStyle(),
+                                                          mWeight,
+                                                          mStretch,
+                                                          mStyle,
                                                           saneData,
                                                           saneLen);
         if (!fe) {
             mFontSet->LogMessage(this, "not usable by platform");
         }
     }
 
     if (fe) {
@@ -929,19 +931,19 @@ gfxUserFontSet::~gfxUserFontSet()
         fp->RemoveUserFontSet(this);
     }
 }
 
 already_AddRefed<gfxUserFontEntry>
 gfxUserFontSet::FindOrCreateUserFontEntry(
                                const nsAString& aFamilyName,
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
-                               WeightRange aWeight,
-                               StretchRange aStretch,
-                               SlantStyleRange aStyle,
+                               FontWeight aWeight,
+                               FontStretch aStretch,
+                               FontSlantStyle aStyle,
                                const nsTArray<gfxFontFeature>& aFeatureSettings,
                                const nsTArray<gfxFontVariation>& aVariationSettings,
                                uint32_t aLanguageOverride,
                                gfxCharacterMap* aUnicodeRanges,
                                uint8_t aFontDisplay)
 {
     RefPtr<gfxUserFontEntry> entry;
 
@@ -969,19 +971,19 @@ gfxUserFontSet::FindOrCreateUserFontEntr
     }
 
     return entry.forget();
 }
 
 already_AddRefed<gfxUserFontEntry>
 gfxUserFontSet::CreateUserFontEntry(
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
-                               WeightRange aWeight,
-                               StretchRange aStretch,
-                               SlantStyleRange aStyle,
+                               FontWeight aWeight,
+                               FontStretch aStretch,
+                               FontSlantStyle aStyle,
                                const nsTArray<gfxFontFeature>& aFeatureSettings,
                                const nsTArray<gfxFontVariation>& aVariationSettings,
                                uint32_t aLanguageOverride,
                                gfxCharacterMap* aUnicodeRanges,
                                uint8_t aFontDisplay)
 {
 
     RefPtr<gfxUserFontEntry> userFontEntry =
@@ -990,25 +992,28 @@ gfxUserFontSet::CreateUserFontEntry(
                               aLanguageOverride, aUnicodeRanges, aFontDisplay);
     return userFontEntry.forget();
 }
 
 gfxUserFontEntry*
 gfxUserFontSet::FindExistingUserFontEntry(
                                gfxUserFontFamily* aFamily,
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
-                               WeightRange aWeight,
-                               StretchRange aStretch,
-                               SlantStyleRange aStyle,
+                               FontWeight aWeight,
+                               FontStretch aStretch,
+                               FontSlantStyle 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 =
@@ -1030,27 +1035,23 @@ gfxUserFontSet::FindExistingUserFontEntr
 void
 gfxUserFontSet::AddUserFontEntry(const nsAString& aFamilyName,
                                  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: %s display: %d",
+        LOG(("userfonts (%p) added to \"%s\" (%p) style: %s weight: %g "
+             "stretch: %g%% display: %d",
              this, NS_ConvertUTF16toUTF8(aFamilyName).get(), aUserFontEntry,
              (aUserFontEntry->IsItalic() ? "italic" :
               (aUserFontEntry->IsOblique() ? "oblique" : "normal")),
-             weightString.get(),
-             stretchString.get(),
+             aUserFontEntry->Weight().ToFloat(),
+             aUserFontEntry->Stretch().Percentage(),
              aUserFontEntry->GetFontDisplay()));
     }
 }
 
 void
 gfxUserFontSet::IncrementGeneration(bool aIsRebuild)
 {
     // add one, increment again if zero
@@ -1176,19 +1177,19 @@ gfxUserFontSet::UserFontCache::Entry::Ke
             return false;
         }
     }
 
     if (mPrivate != aKey->mPrivate) {
         return false;
     }
 
-    if (mFontEntry->SlantStyle()      != fe->SlantStyle()     ||
-        mFontEntry->Weight()          != fe->Weight()         ||
-        mFontEntry->Stretch()         != fe->Stretch()        ||
+    if (mFontEntry->mStyle            != fe->mStyle     ||
+        mFontEntry->mWeight           != fe->mWeight          ||
+        mFontEntry->mStretch          != fe->mStretch         ||
         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,21 +181,18 @@ 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
@@ -231,33 +228,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,
-                              WeightRange aWeight,
-                              StretchRange aStretch,
-                              SlantStyleRange aStyle,
+                              FontWeight aWeight,
+                              FontStretch aStretch,
+                              FontSlantStyle 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,
-                               WeightRange aWeight,
-                               StretchRange aStretch,
-                               SlantStyleRange aStyle,
+                               FontWeight aWeight,
+                               FontStretch aStretch,
+                               FontSlantStyle 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,
@@ -406,19 +403,20 @@ 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().AsScalar(),
-                                            aKey->mFontEntry->SlantStyle().AsScalar(),
-                                            aKey->mFontEntry->Stretch().AsScalar(),
+                                            aKey->mFontEntry->mWeight.ForHash(),
+                                            // XXX Is this right?
+                                            aKey->mFontEntry->mStyle.ForHash(),
+                                            aKey->mFontEntry->mStretch.ForHash(),
                                             aKey->mFontEntry->mLanguageOverride);
             }
 
             enum { ALLOW_MEMMOVE = false };
 
             gfxFontSrcURI* GetURI() const { return mURI; }
             gfxFontSrcPrincipal* GetPrincipal() const { return mPrincipal; }
             gfxFontEntry* GetFontEntry() const { return mFontEntry; }
@@ -499,19 +497,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,
-                                   WeightRange aWeight,
-                                   StretchRange aStretch,
-                                   SlantStyleRange aStyle,
+                                   FontWeight aWeight,
+                                   FontStretch aStretch,
+                                   FontSlantStyle 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
@@ -539,42 +537,46 @@ 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,
-                     WeightRange aWeight,
-                     StretchRange aStretch,
-                     SlantStyleRange aStyle,
+                     FontWeight aWeight,
+                     FontStretch aStretch,
+                     FontSlantStyle 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,
-                 WeightRange aWeight,
-                 StretchRange aStretch,
-                 SlantStyleRange aStyle,
+                 FontWeight aWeight,
+                 FontStretch aStretch,
+                 FontSlantStyle 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,
-          WeightRange aWeight,
-          StretchRange aStretch,
-          SlantStyleRange aStyle,
+          FontWeight aWeight,
+          FontStretch aStretch,
+          FontSlantStyle 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,108 +984,87 @@ 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);
-  WeightRange weight = GetWeightRangeForDescriptor(val);
+  FontWeight weight = GetWeightForDescriptor(val);
 
   // set up stretch
   aFontFace->GetDesc(eCSSFontDesc_Stretch, val);
-  StretchRange stretch = GetStretchRangeForDescriptor(val);
+  FontStretch stretch = GetStretchForDescriptor(val);
 
   // set up font style
   aFontFace->GetDesc(eCSSFontDesc_Style, val);
-  SlantStyleRange italicStyle = GetStyleRangeForDescriptor(val);
+  FontSlantStyle italicStyle = GetStyleForDescriptor(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,
@@ -1303,28 +1282,24 @@ FontFaceSet::LogMessage(gfxUserFontEntry
   if (!console) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   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:%s src index:%d)",
+        "(font-family: \"%s\" style:%s weight:%g stretch:%g%% src index:%d)",
         aMessage,
         familyName.get(),
-        aUserFontEntry->IsItalic() ? "italic" : "normal", // XXX todo: oblique?
-        weightString.get(),
-        stretchString.get(),
+        aUserFontEntry->IsItalic() ? "italic" : "normal",
+        aUserFontEntry->Weight().ToFloat(),
+        aUserFontEntry->Stretch().Percentage(),
         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;
@@ -1985,19 +1960,19 @@ FontFaceSet::UserFontSet::DoRebuildUserF
     return;
   }
   mFontFaceSet->MarkUserFontSetDirty();
 }
 
 /* virtual */ already_AddRefed<gfxUserFontEntry>
 FontFaceSet::UserFontSet::CreateUserFontEntry(
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
-                               WeightRange aWeight,
-                               StretchRange aStretch,
-                               SlantStyleRange aStyle,
+                               FontWeight aWeight,
+                               FontStretch aStretch,
+                               FontSlantStyle 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,
-                                   WeightRange aWeight,
-                                   StretchRange aStretch,
-                                   SlantStyleRange aStyle,
+                                   FontWeight aWeight,
+                                   FontStretch aStretch,
+                                   FontSlantStyle aStyle,
                                    const nsTArray<gfxFontFeature>& aFeatureSettings,
                                    const nsTArray<gfxFontVariation>& aVariationSettings,
                                    uint32_t aLanguageOverride,
                                    gfxCharacterMap* aUnicodeRanges,
                                    uint8_t aFontDisplay) override;
 
   private:
     RefPtr<FontFaceSet> mFontFaceSet;