Bug 1436048: Use user defined types for font-stretch / font-style. r=jfkthame,jwatt
authorJonathan Watt <jwatt@jwatt.org>
Mon, 23 Apr 2018 16:52:20 +0200
changeset 415107 6ad2ef987c9f7823be13c51bb5dbb23fcf00f182
parent 415106 e366b3efb7482a13a72e1d3e4f124bda870332cf
child 415108 9f1091690e59bcbbe9be04d41ee9637e6d6db31b
push id33889
push useraciure@mozilla.com
push dateTue, 24 Apr 2018 01:14:50 +0000
treeherdermozilla-central@b35a1f66c452 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjfkthame, jwatt
bugs1436048
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1436048: Use user defined types for font-stretch / font-style. r=jfkthame,jwatt Co-authored-by: Emilio Cobos Álvarez <emilio@crisal.io> MozReview-Commit-ID: 7ONYtICeAqb
accessible/base/StyleInfo.cpp
accessible/base/StyleInfo.h
accessible/base/TextAttrs.cpp
accessible/base/TextAttrs.h
dom/mathml/nsMathMLElement.cpp
gfx/2d/ScaledFontDWrite.cpp
gfx/src/FontPropertyTypes.h
gfx/src/nsFont.h
gfx/thebes/gfxDWriteCommon.h
gfx/thebes/gfxDWriteFontList.cpp
gfx/thebes/gfxDWriteFontList.h
gfx/thebes/gfxFT2FontList.cpp
gfx/thebes/gfxFT2FontList.h
gfx/thebes/gfxFcPlatformFontList.cpp
gfx/thebes/gfxFcPlatformFontList.h
gfx/thebes/gfxFont.cpp
gfx/thebes/gfxFont.h
gfx/thebes/gfxFontEntry.cpp
gfx/thebes/gfxFontEntry.h
gfx/thebes/gfxGDIFontList.cpp
gfx/thebes/gfxGDIFontList.h
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/gfxTextRun.cpp
gfx/thebes/gfxUserFontSet.cpp
gfx/thebes/gfxUserFontSet.h
layout/generic/MathMLTextRunFactory.cpp
layout/mathml/nsMathMLTokenFrame.cpp
layout/style/FontFace.h
layout/style/FontFaceSet.cpp
layout/style/FontFaceSet.h
layout/style/GenericSpecifiedValues.h
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
layout/style/ServoBindings.toml
layout/style/nsCSSProps.cpp
layout/style/nsCSSValue.cpp
layout/style/nsCSSValue.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsStyleConsts.h
layout/style/nsStyleUtil.cpp
layout/style/nsStyleUtil.h
servo/components/style/gecko/rules.rs
servo/components/style/gecko_bindings/sugar/ns_css_value.rs
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/longhand/font.mako.rs
servo/components/style/values/computed/font.rs
servo/ports/geckolib/glue.rs
widget/android/nsLookAndFeel.cpp
widget/cocoa/nsLookAndFeel.mm
widget/gtk/nsLookAndFeel.cpp
widget/headless/HeadlessLookAndFeelGTK.cpp
widget/uikit/nsLookAndFeel.mm
widget/windows/nsLookAndFeel.cpp
--- a/accessible/base/StyleInfo.cpp
+++ b/accessible/base/StyleInfo.cpp
@@ -98,23 +98,15 @@ StyleInfo::FormatColor(const nscolor& aV
   aFormattedValue.AppendLiteral(", ");
   aFormattedValue.AppendInt(NS_GET_G(aValue));
   aFormattedValue.AppendLiteral(", ");
   aFormattedValue.AppendInt(NS_GET_B(aValue));
   aFormattedValue.Append(')');
 }
 
 void
-StyleInfo::FormatFontStyle(const nscoord& aValue, nsAString& aFormattedValue)
-{
-  nsCSSKeyword keyword =
-    nsCSSProps::ValueToKeywordEnum(aValue, nsCSSProps::kFontStyleKTable);
-  AppendUTF8toUTF16(nsCSSKeywords::GetStringValue(keyword), aFormattedValue);
-}
-
-void
 StyleInfo::FormatTextDecorationStyle(uint8_t aValue, nsAString& aFormattedValue)
 {
   nsCSSKeyword keyword =
     nsCSSProps::ValueToKeywordEnum(aValue,
                                    nsCSSProps::kTextDecorationStyleKTable);
   AppendUTF8toUTF16(nsCSSKeywords::GetStringValue(keyword), aFormattedValue);
 }
--- a/accessible/base/StyleInfo.h
+++ b/accessible/base/StyleInfo.h
@@ -26,17 +26,16 @@ public:
   void TextAlign(nsAString& aValue);
   void TextIndent(nsAString& aValue);
   void MarginLeft(nsAString& aValue) { Margin(eSideLeft, aValue); }
   void MarginRight(nsAString& aValue) { Margin(eSideRight, aValue); }
   void MarginTop(nsAString& aValue) { Margin(eSideTop, aValue); }
   void MarginBottom(nsAString& aValue) { Margin(eSideBottom, aValue); }
 
   static void FormatColor(const nscolor& aValue, nsString& aFormattedValue);
-  static void FormatFontStyle(const nscoord& aValue, nsAString& aFormattedValue);
   static void FormatTextDecorationStyle(uint8_t aValue, nsAString& aFormattedValue);
 
 private:
   StyleInfo() = delete;
   StyleInfo(const StyleInfo&) = delete;
   StyleInfo& operator = (const StyleInfo&) = delete;
 
   void Margin(Side aSide, nsAString& aValue);
--- a/accessible/base/TextAttrs.cpp
+++ b/accessible/base/TextAttrs.cpp
@@ -9,16 +9,17 @@
 #include "nsAccUtils.h"
 #include "nsCoreUtils.h"
 #include "StyleInfo.h"
 
 #include "gfxFont.h"
 #include "nsFontMetrics.h"
 #include "nsLayoutUtils.h"
 #include "nsContainerFrame.h"
+#include "nsStyleUtil.h"
 #include "HyperTextAccessible.h"
 #include "mozilla/AppUnits.h"
 #include "mozilla/gfx/2D.h"
 
 using namespace mozilla;
 using namespace mozilla::a11y;
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -544,50 +545,50 @@ TextAttrsMgr::FontSizeTextAttr::
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // FontStyleTextAttr
 ////////////////////////////////////////////////////////////////////////////////
 
 TextAttrsMgr::FontStyleTextAttr::
   FontStyleTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
-  TTextAttr<nscoord>(!aFrame)
+  TTextAttr<FontSlantStyle>(!aFrame)
 {
   mRootNativeValue = aRootFrame->StyleFont()->mFont.style;
   mIsRootDefined = true;
 
   if (aFrame) {
     mNativeValue = aFrame->StyleFont()->mFont.style;
     mIsDefined = true;
   }
 }
 
 bool
 TextAttrsMgr::FontStyleTextAttr::
-  GetValueFor(Accessible* aAccessible, nscoord* aValue)
+  GetValueFor(Accessible* aAccessible, FontSlantStyle* aValue)
 {
   nsIContent* elm = nsCoreUtils::GetDOMElementFor(aAccessible->GetContent());
   if (elm) {
     nsIFrame* frame = elm->GetPrimaryFrame();
     if (frame) {
       *aValue = frame->StyleFont()->mFont.style;
       return true;
     }
   }
   return false;
 }
 
 void
 TextAttrsMgr::FontStyleTextAttr::
-  ExposeValue(nsIPersistentProperties* aAttributes, const nscoord& aValue)
+  ExposeValue(nsIPersistentProperties* aAttributes,
+              const FontSlantStyle& aValue)
 {
-  nsAutoString formattedValue;
-  StyleInfo::FormatFontStyle(aValue, formattedValue);
-
-  nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::font_style, formattedValue);
+  nsAutoString string;
+  nsStyleUtil::AppendFontSlantStyle(aValue, string);
+  nsAccUtils::SetAccAttr(aAttributes, nsGkAtoms::font_style, string);
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 // FontWeightTextAttr
 ////////////////////////////////////////////////////////////////////////////////
 
 TextAttrsMgr::FontWeightTextAttr::
--- a/accessible/base/TextAttrs.h
+++ b/accessible/base/TextAttrs.h
@@ -331,29 +331,29 @@ protected:
   private:
     nsDeviceContext* mDC;
   };
 
 
   /**
    * Class is used for the work with "font-style" text attribute.
    */
-  class FontStyleTextAttr : public TTextAttr<nscoord>
+  class FontStyleTextAttr : public TTextAttr<mozilla::FontSlantStyle>
   {
   public:
     FontStyleTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame);
     virtual ~FontStyleTextAttr() { }
 
   protected:
 
     // TTextAttr
-    virtual bool GetValueFor(Accessible* aContent, nscoord* aValue)
+    virtual bool GetValueFor(Accessible* aContent, mozilla::FontSlantStyle* aValue)
       override;
     virtual void ExposeValue(nsIPersistentProperties* aAttributes,
-                             const nscoord& aValue) override;
+                             const mozilla::FontSlantStyle& aValue) override;
   };
 
 
   /**
    * Class is used for the work with "font-weight" text attribute.
    */
   class FontWeightTextAttr : public TTextAttr<mozilla::FontWeight>
   {
--- a/dom/mathml/nsMathMLElement.cpp
+++ b/dom/mathml/nsMathMLElement.cpp
@@ -691,22 +691,22 @@ nsMathMLElement::MapMathMLAttributesInto
   if (value) {
     WarnDeprecated(nsGkAtoms::fontstyle_->GetUTF16String(),
                    nsGkAtoms::mathvariant_->GetUTF16String(),
                    aData->Document());
     if (value->Type() == nsAttrValue::eString &&
         !aData->PropertyIsSet(eCSSProperty_font_style)) {
       nsAutoString str(value->GetStringValue());
       str.CompressWhitespace();
+      // FIXME(emilio): This should use FontSlantStyle or what not. Or even
+      // better, it looks deprecated since forever, we should just kill it.
       if (str.EqualsASCII("normal")) {
-        aData->SetKeywordValue(eCSSProperty_font_style,
-                               NS_STYLE_FONT_STYLE_NORMAL);
+        aData->SetKeywordValue(eCSSProperty_font_style, NS_FONT_STYLE_NORMAL);
       } else if (str.EqualsASCII("italic")) {
-        aData->SetKeywordValue(eCSSProperty_font_style,
-                               NS_STYLE_FONT_STYLE_ITALIC);
+        aData->SetKeywordValue(eCSSProperty_font_style, NS_FONT_STYLE_ITALIC);
       }
     }
   }
 
   // fontweight
   //
   // "Specified the font weight for the token. Deprecated in favor of
   // mathvariant."
--- a/gfx/2d/ScaledFontDWrite.cpp
+++ b/gfx/2d/ScaledFontDWrite.cpp
@@ -4,16 +4,17 @@
  * 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/. */
 
 #include "ScaledFontDWrite.h"
 #include "UnscaledFontDWrite.h"
 #include "PathD2D.h"
 #include "gfxFont.h"
 #include "Logging.h"
+#include "mozilla/FontPropertyTypes.h"
 #include "mozilla/webrender/WebRenderTypes.h"
 
 #include "dwrite_3.h"
 
 // Currently, we build with WINVER=0x601 (Win7), which means newer
 // declarations in dwrite_3.h will not be visible. Also, we don't
 // yet have the Fall Creators Update SDK available on build machines,
 // so even with updated WINVER, some of the interfaces we need would
@@ -88,41 +89,47 @@ DoGrayscale(IDWriteFontFace *aDWFace, Fl
       }
     }
     aDWFace->ReleaseFontTable(tableContext);
   }
   return true;
 }
 
 static inline DWRITE_FONT_STRETCH
-DWriteFontStretchFromStretch(uint16_t aStretch)
+DWriteFontStretchFromStretch(FontStretch aStretch)
 {
-    switch (aStretch) {
-        case NS_FONT_STRETCH_ULTRA_CONDENSED:
-            return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
-        case NS_FONT_STRETCH_EXTRA_CONDENSED:
-            return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
-        case NS_FONT_STRETCH_CONDENSED:
-            return DWRITE_FONT_STRETCH_CONDENSED;
-        case NS_FONT_STRETCH_SEMI_CONDENSED:
-            return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
-        case NS_FONT_STRETCH_NORMAL:
-            return DWRITE_FONT_STRETCH_NORMAL;
-        case NS_FONT_STRETCH_SEMI_EXPANDED:
-            return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
-        case NS_FONT_STRETCH_EXPANDED:
-            return DWRITE_FONT_STRETCH_EXPANDED;
-        case NS_FONT_STRETCH_EXTRA_EXPANDED:
-            return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
-        case NS_FONT_STRETCH_ULTRA_EXPANDED:
-            return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
-        default:
-            return DWRITE_FONT_STRETCH_UNDEFINED;
+    if (aStretch == FontStretch::UltraCondensed()) {
+        return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
+    }
+    if (aStretch == FontStretch::ExtraCondensed()) {
+        return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
+    }
+    if (aStretch == FontStretch::Condensed()) {
+        return DWRITE_FONT_STRETCH_CONDENSED;
+    }
+    if (aStretch == FontStretch::SemiCondensed()) {
+        return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
+    }
+    if (aStretch == FontStretch::Normal()) {
+        return DWRITE_FONT_STRETCH_NORMAL;
     }
-}
+    if (aStretch == FontStretch::SemiExpanded()) {
+        return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
+    }
+    if (aStretch == FontStretch::Expanded()) {
+        return DWRITE_FONT_STRETCH_EXPANDED;
+    }
+    if (aStretch == FontStretch::ExtraExpanded()) {
+        return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
+    }
+    if (aStretch == FontStretch::UltraExpanded()) {
+        return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
+    }
+    return DWRITE_FONT_STRETCH_UNDEFINED;
+ }
 
 ScaledFontDWrite::ScaledFontDWrite(IDWriteFontFace *aFontFace,
                                    const RefPtr<UnscaledFont>& aUnscaledFont,
                                    Float aSize,
                                    bool aUseEmbeddedBitmap,
                                    bool aForceGDIMode,
                                    IDWriteRenderingParams* aParams,
                                    Float aGamma,
@@ -134,17 +141,18 @@ ScaledFontDWrite::ScaledFontDWrite(IDWri
     , mForceGDIMode(aForceGDIMode)
     , mParams(aParams)
     , mGamma(aGamma)
     , mContrast(aContrast)
 {
   if (aStyle) {
     mStyle = SkFontStyle(aStyle->weight.ToIntRounded(),
                          DWriteFontStretchFromStretch(aStyle->stretch),
-                         aStyle->style == NS_FONT_STYLE_NORMAL ?
+                         // FIXME(jwatt): also use kOblique_Slant
+                         aStyle->style ==  FontSlantStyle::Normal()?
                          SkFontStyle::kUpright_Slant : SkFontStyle::kItalic_Slant);
   }
 }
 
 already_AddRefed<Path>
 ScaledFontDWrite::GetPathForGlyphs(const GlyphBuffer &aBuffer, const DrawTarget *aTarget)
 {
   if (aTarget->GetBackendType() != BackendType::DIRECT2D && aTarget->GetBackendType() != BackendType::DIRECT2D1_1) {
--- a/gfx/src/FontPropertyTypes.h
+++ b/gfx/src/FontPropertyTypes.h
@@ -6,45 +6,47 @@
 /* font specific types shared by both thebes and layout */
 
 #ifndef GFX_FONT_PROPERTY_TYPES_H
 #define GFX_FONT_PROPERTY_TYPES_H
 
 #include <cstdint>
 #include <cmath>
 #include "mozilla/Assertions.h"
+#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 {
 
 /**
  * Generic template for font property type classes that use a fixed-point
  * internal representation.
  * Template parameters:
- *   T - the integer type to use as the internal representation (e.g. uint16_t)
+ *   InternalType - the integer type to use as the internal representation (e.g.
+ *                  uint16_t)
  *       * NOTE that T must NOT be plain /int/, as that would result in
  *         ambiguity between constructors from /int/ and /T/, which mean
  *         different things.
  *   FractionBits - number of bits to use for the fractional part
  *   Min, Max - [inclusive] limits to the range of values that may be stored
  * Values are constructed from and exposed as floating-point, but stored
  * internally as fixed point, so there will be a quantization effect on
  * fractional values, depending on the number of fractional bits used.
  * Using (16-bit) fixed-point types rather than floats for these style
- * attributes reduces the memory footprint of gfxFontEntry and gfxFontStyle;
+ * 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 T,unsigned FractionBits,int Min,int Max>
+template<class InternalType, unsigned FractionBits, int Min, int Max>
 class FontPropertyValue
 {
 public:
   // Ugh. We need a default constructor to allow this type to be used in the
   // union in nsCSSValue. Furthermore we need the default and copy
   // 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
@@ -83,62 +85,61 @@ 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.
-  T ForHash() const
+  InternalType ForHash() const
   {
     return mValue;
   }
 
+  static constexpr const float kMin = float(Min);
+  static constexpr const float kMax = float(Max);
+
 protected:
-  typedef T internal_type;
-
   // Construct from a floating-point or integer value, checking that it is
   // within the allowed range and converting to fixed-point representation.
   explicit FontPropertyValue(float aValue)
     : mValue(std::round(aValue * kScale))
   {
     MOZ_ASSERT(aValue >= kMin && aValue <= kMax);
   }
   explicit FontPropertyValue(int aValue)
     : mValue(aValue << kFractionBits)
   {
     MOZ_ASSERT(aValue >= Min && aValue <= Max);
   }
 
   // Construct directly from a fixed-point value of type T, with no check;
   // note that there may be special "flag" values that are outside the normal
   // min/max range (e.g. for font-style:italic, distinct from oblique angle).
-  explicit FontPropertyValue(T aValue)
+  explicit FontPropertyValue(InternalType aValue)
     : mValue(aValue)
   {
   }
 
   // This is protected as it may not be the most appropriate accessor for a
   // given instance to expose. It's up to each individual property to provide
   // public accessors that forward to this as required.
   float ToFloat() const { return mValue * kInverseScale; }
   int ToIntRounded() const { return (mValue + kPointFive) >> FractionBits; }
 
   static constexpr float kScale = float(1u << FractionBits);
   static constexpr float kInverseScale = 1.0f / kScale;
-  static constexpr float kMin = float(Min);
-  static constexpr float kMax = float(Max);
   static const unsigned kFractionBits = FractionBits;
 
   // Constant representing 0.5 in the internal representation (note this
   // assumes that kFractionBits is greater than zero!)
-  static const T kPointFive = 1u << (kFractionBits - 1);
+  static const InternalType kPointFive = 1u << (kFractionBits - 1);
 
-  T mValue;
+  InternalType mValue;
 };
 
 /**
  * font-weight: range 1..1000, fractional values permitted; keywords
  * 'normal', 'bold' aliased to 400, 700 respectively; relative keywords
  * 'lighter', 'bolder' (not currently handled here).
  *
  * We use an unsigned 10.6 fixed-point value (range 0.0 - 1023.984375)
@@ -181,26 +182,28 @@ 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:
-  explicit FontWeight(internal_type aValue)
+  typedef uint16_t InternalType;
+
+  explicit FontWeight(InternalType aValue)
     : FontPropertyValue(aValue)
   {
   }
 
-  static const internal_type kNormal        = 400u << kFractionBits;
-  static const internal_type kBold          = 700u << kFractionBits;
-  static const internal_type kBoldThreshold = 600u << kFractionBits;
-  static const internal_type kThin          = 100u << kFractionBits;
-  static const internal_type kExtraBold     = 900u << kFractionBits;
+  static const InternalType kNormal        = 400u << kFractionBits;
+  static const InternalType kBold          = 700u << kFractionBits;
+  static const InternalType kBoldThreshold = 600u << kFractionBits;
+  static const InternalType kThin          = 100u << kFractionBits;
+  static const InternalType kExtraBold     = 900u << kFractionBits;
 };
 
 /**
  * font-stretch is represented as a percentage relative to 'normal'.
  *
  * css-fonts says the value must be >= 0%, and normal is 100%. Keywords
  * from ultra-condensed to ultra-expanded are aliased to percentages
  * from 50% to 200%; values outside that range are unlikely to be common,
@@ -260,77 +263,92 @@ public:
   {
     return FontStretch(kUltraExpanded);
   }
 
   bool IsNormal() const { return mValue == kNormal; }
   float Percentage() const { return ToFloat(); }
 
 private:
-  static const internal_type kUltraCondensed =  50u << kFractionBits;
-  static const internal_type kExtraCondensed = (62u << kFractionBits) + kPointFive;
-  static const internal_type kCondensed      =  75u << kFractionBits;
-  static const internal_type kSemiCondensed  = (87u << kFractionBits) + kPointFive;
-  static const internal_type kNormal         = 100u << kFractionBits;
-  static const internal_type kSemiExpanded  = (112u << kFractionBits) + kPointFive;
-  static const internal_type kExpanded       = 125u << kFractionBits;
-  static const internal_type kExtraExpanded  = 150u << kFractionBits;
-  static const internal_type kUltraExpanded  = 200u << kFractionBits;
+  typedef uint16_t InternalType;
+
+  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;
+  static const InternalType kSemiCondensed  = (87u << kFractionBits) + kPointFive;
+  static const InternalType kNormal         = 100u << kFractionBits;
+  static const InternalType kSemiExpanded  = (112u << kFractionBits) + kPointFive;
+  static const InternalType kExpanded       = 125u << kFractionBits;
+  static const InternalType kExtraExpanded  = 150u << kFractionBits;
+  static const InternalType kUltraExpanded  = 200u << kFractionBits;
 };
 
 /**
  * font-style: normal | italic | oblique <angle>?
  * values of <angle> below -90 or above 90 not permitted
  * - Use a signed 8.8 fixed-point value
  *   (representable range -128.0 - 127.99609375)
  * - Define min value (-128.0) as meaning 'normal'
  * - Define max value (127.99609375) as 'italic'
  * - Other values represent 'oblique <angle>'
  * - Note that 'oblique 0deg' is distinct from 'normal' (should it be?)
  */
-class FontStyle final : public FontPropertyValue<int16_t,8,-90,90>
+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.
-  FontStyle() = default;
+  FontSlantStyle() = default;
 
-  static FontStyle Normal()
+  static FontSlantStyle Normal()
   {
-    return FontStyle(kNormal);
+    return FontSlantStyle(kNormal);
   }
 
-  static FontStyle Italic()
+  static FontSlantStyle Italic()
   {
-    return FontStyle(kItalic);
+    return FontSlantStyle(kItalic);
   }
 
-  static FontStyle Oblique(float aAngle = 14.0f)
+  static FontSlantStyle Oblique(float aAngle = kDefaultAngle)
   {
-    return FontStyle(aAngle);
+    return FontSlantStyle(aAngle);
   }
 
   bool IsNormal() const { return mValue == kNormal; }
   bool IsItalic() const { return mValue == kItalic; }
   bool IsOblique() const { return mValue != kItalic && mValue != kNormal; }
 
   float ObliqueAngle() const
   {
     // It's not meaningful to get the oblique angle from a style that is
     // actually 'normal' or 'italic'.
-    MOZ_ASSERT(!IsItalic() && !IsNormal());
+    MOZ_ASSERT(IsOblique());
     return ToFloat();
   }
 
 private:
-  explicit FontStyle(float aAngle)
+  explicit FontSlantStyle(InternalType aConstant)
+    : FontPropertyValue(aConstant)
+  {
+  }
+
+  explicit FontSlantStyle(float aAngle)
     : FontPropertyValue(aAngle)
   {
   }
 
-  static const int16_t kNormal = INT16_MIN;
-  static const int16_t kItalic = INT16_MAX;
+  static const InternalType kNormal = INT16_MIN;
+  static const InternalType kItalic = INT16_MAX;
 };
 
 } // namespace mozilla
 
 #endif // GFX_FONT_PROPERTY_TYPES_H
 
--- a/gfx/src/nsFont.h
+++ b/gfx/src/nsFont.h
@@ -40,24 +40,23 @@ const uint8_t kGenericFont_moz_fixed    
 const uint8_t kGenericFont_serif        = 0x02;
 const uint8_t kGenericFont_sans_serif   = 0x04;
 const uint8_t kGenericFont_monospace    = 0x08;
 const uint8_t kGenericFont_cursive      = 0x10;
 const uint8_t kGenericFont_fantasy      = 0x20;
 
 // Font structure.
 struct nsFont {
+  typedef mozilla::FontStretch FontStretch;
+  typedef mozilla::FontSlantStyle FontSlantStyle;
   typedef mozilla::FontWeight FontWeight;
 
   // list of font families, either named or generic
   mozilla::FontFamilyList fontlist;
 
-  // The style of font (normal, italic, oblique; see gfxFontConstants.h)
-  uint8_t style = NS_FONT_STYLE_NORMAL;
-
   // Force this font to not be considered a 'generic' font, even if
   // the name is the same as a CSS generic font family.
   bool systemFont = false;
 
   // Variant subproperties
   uint8_t variantCaps = NS_FONT_VARIANT_CAPS_NORMAL;
   uint8_t variantNumeric = NS_FONT_VARIANT_NUMERIC_NORMAL;
   uint8_t variantPosition = NS_FONT_VARIANT_POSITION_NORMAL;
@@ -75,22 +74,19 @@ struct nsFont {
 
   // Smoothing - controls subpixel-antialiasing (currently OSX only)
   uint8_t smoothing = NS_FONT_SMOOTHING_AUTO;
 
   // The estimated background color behind the text. Enables a special
   // rendering mode when NS_GET_A(.) > 0. Only used for text in the chrome.
   nscolor fontSmoothingBackgroundColor = NS_RGBA(0,0,0,0);
 
-  // The weight of the font; see gfxFontConstants.h.
+  FontSlantStyle style = FontSlantStyle::Normal();
   FontWeight weight = FontWeight::Normal();
-
-  // The stretch of the font (the sum of various NS_FONT_STRETCH_*
-  // constants; see gfxFontConstants.h).
-  int16_t stretch = NS_FONT_STRETCH_NORMAL;
+  FontStretch stretch = FontStretch::Normal();
 
   // Kerning
   uint8_t kerning = NS_FONT_KERNING_AUTO;
 
   // Whether automatic optical sizing should be applied to variation fonts
   // that include an 'opsz' axis
   uint8_t opticalSizing = NS_FONT_OPTICAL_SIZING_AUTO;
 
--- a/gfx/thebes/gfxDWriteCommon.h
+++ b/gfx/thebes/gfxDWriteCommon.h
@@ -3,79 +3,86 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef GFX_DWRITECOMMON_H
 #define GFX_DWRITECOMMON_H
 
 // Mozilla includes
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/FontPropertyTypes.h"
 #include "nscore.h"
 #include "nsIServiceManager.h"
 #include "nsCOMPtr.h"
 #include "cairo-features.h"
 #include "gfxFontConstants.h"
 #include "nsTArray.h"
 #include "gfxWindowsPlatform.h"
 #include "nsIUUIDGenerator.h"
 
 #include <windows.h>
 #include <dwrite.h>
 
 static inline DWRITE_FONT_STRETCH
-DWriteFontStretchFromStretch(uint16_t aStretch)
+DWriteFontStretchFromStretch(mozilla::FontStretch aStretch)
 {
-    switch (aStretch) {
-        case NS_FONT_STRETCH_ULTRA_CONDENSED:
-            return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
-        case NS_FONT_STRETCH_EXTRA_CONDENSED:
-            return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
-        case NS_FONT_STRETCH_CONDENSED:
-            return DWRITE_FONT_STRETCH_CONDENSED;
-        case NS_FONT_STRETCH_SEMI_CONDENSED:
-            return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
-        case NS_FONT_STRETCH_NORMAL:
-            return DWRITE_FONT_STRETCH_NORMAL;
-        case NS_FONT_STRETCH_SEMI_EXPANDED:
-            return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
-        case NS_FONT_STRETCH_EXPANDED:
-            return DWRITE_FONT_STRETCH_EXPANDED;
-        case NS_FONT_STRETCH_EXTRA_EXPANDED:
-            return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
-        case NS_FONT_STRETCH_ULTRA_EXPANDED:
-            return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
-        default:
-            return DWRITE_FONT_STRETCH_UNDEFINED;
+    if (aStretch == mozilla::FontStretch::UltraCondensed()) {
+        return DWRITE_FONT_STRETCH_ULTRA_CONDENSED;
+    }
+    if (aStretch == mozilla::FontStretch::ExtraCondensed()) {
+        return DWRITE_FONT_STRETCH_EXTRA_CONDENSED;
+    }
+    if (aStretch == mozilla::FontStretch::Condensed()) {
+        return DWRITE_FONT_STRETCH_CONDENSED;
+    }
+    if (aStretch == mozilla::FontStretch::SemiCondensed()) {
+        return DWRITE_FONT_STRETCH_SEMI_CONDENSED;
     }
+    if (aStretch == mozilla::FontStretch::Normal()) {
+        return DWRITE_FONT_STRETCH_NORMAL;
+    }
+    if (aStretch == mozilla::FontStretch::SemiExpanded()) {
+        return DWRITE_FONT_STRETCH_SEMI_EXPANDED;
+    }
+    if (aStretch == mozilla::FontStretch::Expanded()) {
+        return DWRITE_FONT_STRETCH_EXPANDED;
+    }
+    if (aStretch == mozilla::FontStretch::ExtraExpanded()) {
+        return DWRITE_FONT_STRETCH_EXTRA_EXPANDED;
+    }
+    if (aStretch == mozilla::FontStretch::UltraExpanded()) {
+        return DWRITE_FONT_STRETCH_ULTRA_EXPANDED;
+    }
+    return DWRITE_FONT_STRETCH_UNDEFINED;
 }
 
-static inline uint16_t
+static inline mozilla::FontStretch
 FontStretchFromDWriteStretch(DWRITE_FONT_STRETCH aStretch)
 {
     switch (aStretch) {
         case DWRITE_FONT_STRETCH_ULTRA_CONDENSED:
-            return NS_FONT_STRETCH_ULTRA_CONDENSED;
+            return mozilla::FontStretch::UltraCondensed();
         case DWRITE_FONT_STRETCH_EXTRA_CONDENSED:
-            return NS_FONT_STRETCH_EXTRA_CONDENSED;
+            return mozilla::FontStretch::ExtraCondensed();
         case DWRITE_FONT_STRETCH_CONDENSED:
-            return NS_FONT_STRETCH_CONDENSED;
+            return mozilla::FontStretch::Condensed();
         case DWRITE_FONT_STRETCH_SEMI_CONDENSED:
-            return NS_FONT_STRETCH_SEMI_CONDENSED;
+            return mozilla::FontStretch::SemiCondensed();
         case DWRITE_FONT_STRETCH_NORMAL:
-            return NS_FONT_STRETCH_NORMAL;
+            return mozilla::FontStretch::Normal();
         case DWRITE_FONT_STRETCH_SEMI_EXPANDED:
-            return NS_FONT_STRETCH_SEMI_EXPANDED;
+            return mozilla::FontStretch::SemiExpanded();
         case DWRITE_FONT_STRETCH_EXPANDED:
-            return NS_FONT_STRETCH_EXPANDED;
+            return mozilla::FontStretch::Expanded();
         case DWRITE_FONT_STRETCH_EXTRA_EXPANDED:
-            return NS_FONT_STRETCH_EXTRA_EXPANDED;
+            return mozilla::FontStretch::ExtraExpanded();
         case DWRITE_FONT_STRETCH_ULTRA_EXPANDED:
-            return NS_FONT_STRETCH_ULTRA_EXPANDED;
+            return mozilla::FontStretch::UltraExpanded();
         default:
-            return NS_FONT_STRETCH_NORMAL;
+            return mozilla::FontStretch::Normal();
     }
 }
 
 class gfxDWriteFontFileLoader : public IDWriteFontFileLoader
 {
 public:
     gfxDWriteFontFileLoader()
     {
--- a/gfx/thebes/gfxDWriteFontList.cpp
+++ b/gfx/thebes/gfxDWriteFontList.cpp
@@ -953,18 +953,18 @@ gfxDWriteFontList::GetDefaultFontForPlat
     }
 
     return nullptr;
 }
 
 gfxFontEntry *
 gfxDWriteFontList::LookupLocalFont(const nsAString& aFontName,
                                    FontWeight aWeight,
-                                   uint16_t aStretch,
-                                   uint8_t aStyle)
+                                   FontStretch aStretch,
+                                   FontSlantStyle aStyle)
 {
     gfxFontEntry *lookup;
 
     lookup = LookupInFaceNameLists(aFontName);
     if (!lookup) {
         return nullptr;
     }
 
@@ -977,18 +977,18 @@ gfxDWriteFontList::LookupLocalFont(const
                                aStyle);
     fe->SetForceGDIClassic(dwriteLookup->GetForceGDIClassic());
     return fe;
 }
 
 gfxFontEntry *
 gfxDWriteFontList::MakePlatformFont(const nsAString& aFontName,
                                     FontWeight aWeight,
-                                    uint16_t aStretch,
-                                    uint8_t aStyle,
+                                    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),
--- a/gfx/thebes/gfxDWriteFontList.h
+++ b/gfx/thebes/gfxDWriteFontList.h
@@ -29,30 +29,31 @@
 #include "cairo-win32.h"
 
 #include "gfxPlatformFontList.h"
 #include "gfxPlatform.h"
 #include <algorithm>
 
 #include "mozilla/gfx/UnscaledFontDWrite.h"
 
-
 /**
  * gfxDWriteFontFamily is a class that describes one of the fonts on the
  * users system.  It holds each gfxDWriteFontEntry (maps more directly to
  * a font face) which holds font type, charset info and character map info.
  */
 class gfxDWriteFontEntry;
 
 /**
  * \brief Class representing directwrite font family.
  */
 class gfxDWriteFontFamily : public gfxFontFamily
 {
 public:
+    typedef mozilla::FontStretch FontStretch;
+    typedef mozilla::FontSlantStyle FontSlantStyle;
     typedef mozilla::FontWeight FontWeight;
 
     /**
      * Constructs a new DWriteFont Family.
      *
      * \param aName Name identifying the family
      * \param aFamily IDWriteFontFamily object representing the directwrite
      * family object.
@@ -110,19 +111,19 @@ public:
                        IDWriteFont *aFont,
                        bool aIsSystemFont = false)
       : gfxFontEntry(aFaceName), mFont(aFont), mFontFile(nullptr),
         mIsSystemFont(aIsSystemFont), mForceGDIClassic(false),
         mHasVariations(false), mHasVariationsInitialized(false)
     {
         DWRITE_FONT_STYLE dwriteStyle = aFont->GetStyle();
         mStyle = (dwriteStyle == DWRITE_FONT_STYLE_ITALIC ?
-                  NS_FONT_STYLE_ITALIC :
+                  FontSlantStyle::Italic() :
                   (dwriteStyle == DWRITE_FONT_STYLE_OBLIQUE ?
-                   NS_FONT_STYLE_OBLIQUE : NS_FONT_STYLE_NORMAL));
+                   FontSlantStyle::Oblique() : FontSlantStyle::Normal()));
         mStretch = FontStretchFromDWriteStretch(aFont->GetStretch());
         int weight = NS_ROUNDUP(aFont->GetWeight() - 50, 100);
 
         weight = mozilla::Clamp(weight, 100, 900);
         mWeight = FontWeight(weight);
 
         mIsCJK = UNINITIALIZED_VALUE;
     }
@@ -134,20 +135,20 @@ public:
      *
      * \param aFaceName The name of the corresponding font face.
      * \param aFont DirectWrite font object
      * \param aWeight Weight of the font
      * \param aStretch Stretch of the font
      * \param aStyle italic or oblique of font
      */
     gfxDWriteFontEntry(const nsAString& aFaceName,
-                              IDWriteFont *aFont,
-                              FontWeight aWeight,
-                              uint16_t aStretch,
-                              uint8_t aStyle)
+                       IDWriteFont *aFont,
+                       FontWeight aWeight,
+                       FontStretch aStretch,
+                       FontSlantStyle aStyle)
       : gfxFontEntry(aFaceName), mFont(aFont), mFontFile(nullptr),
         mIsSystemFont(false), mForceGDIClassic(false),
         mHasVariations(false), mHasVariationsInitialized(false)
     {
         mWeight = aWeight;
         mStretch = aStretch;
         mStyle = aStyle;
         mIsLocalUserFont = true;
@@ -163,18 +164,18 @@ public:
      * \param aWeight Weight of the font
      * \param aStretch Stretch of the font
      * \param aStyle italic or oblique of font
      */
     gfxDWriteFontEntry(const nsAString& aFaceName,
                               IDWriteFontFile *aFontFile,
                               IDWriteFontFileStream *aFontFileStream,
                               FontWeight aWeight,
-                              uint16_t aStretch,
-                              uint8_t aStyle)
+                              FontStretch aStretch,
+                              FontSlantStyle aStyle)
       : gfxFontEntry(aFaceName), mFont(nullptr),
         mFontFile(aFontFile), mFontFileStream(aFontFileStream),
         mIsSystemFont(false), mForceGDIClassic(false),
         mHasVariations(false), mHasVariationsInitialized(false)
     {
         mWeight = aWeight;
         mStretch = aStretch;
         mStyle = aStyle;
@@ -400,23 +401,23 @@ public:
 
     // initialize font lists
     virtual nsresult InitFontListForPlatform() override;
 
     gfxFontFamily* CreateFontFamily(const nsAString& aName) const override;
 
     virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
                                           FontWeight aWeight,
-                                          uint16_t aStretch,
-                                          uint8_t aStyle);
+                                          FontStretch aStretch,
+                                          FontSlantStyle aStyle);
 
     virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
                                            FontWeight aWeight,
-                                           uint16_t aStretch,
-                                           uint8_t aStyle,
+                                           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/gfxFT2FontList.cpp
+++ b/gfx/thebes/gfxFT2FontList.cpp
@@ -253,18 +253,18 @@ FT2FontEntry::CreateFontInstance(const g
     cairo_scaled_font_destroy(scaledFont);
     return font;
 }
 
 /* static */
 FT2FontEntry*
 FT2FontEntry::CreateFontEntry(const nsAString& aFontName,
                               FontWeight aWeight,
-                              uint16_t aStretch,
-                              uint8_t aStyle,
+                              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) {
@@ -326,18 +326,19 @@ FT2FontEntry*
 FT2FontEntry::CreateFontEntry(const FontListEntry& aFLE)
 {
     FT2FontEntry *fe = new FT2FontEntry(aFLE.faceName());
     fe->mFilename = aFLE.filepath();
     fe->mFTFontIndex = aFLE.index();
     // The weight transported across IPC is a float, so we need to explicitly
     // convert it back to a FontWeight.
     fe->mWeight = FontWeight(aFLE.weight());
-    fe->mStretch = aFLE.stretch();
-    fe->mStyle = (aFLE.italic() ? NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL);
+    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);
@@ -386,17 +387,17 @@ FT2FontEntry*
 FT2FontEntry::CreateFontEntry(FT_Face aFace,
                               const char* aFilename, uint8_t aIndex,
                               const nsAString& aName,
                               const uint8_t* aFontData,
                               uint32_t aLength)
 {
     FT2FontEntry *fe = new FT2FontEntry(aName);
     fe->mStyle = (FTFaceIsItalic(aFace) ?
-                  NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL);
+                  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 :
@@ -661,21 +662,24 @@ FT2FontFamily::AddFacesToFontList(Infall
         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(),
+        aFontList->AppendElement(FontListEntry(Name(),
+                                               fe->Name(),
                                                fe->mFilename,
                                                fe->Weight().ToFloat(),
-                                               fe->Stretch(),
-                                               fe->mStyle,
+                                               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.
@@ -988,17 +992,18 @@ AppendToFaceList(nsCString& aFaceList,
     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().ToFloat());
     aFaceList.Append(',');
-    aFaceList.AppendInt(aFontEntry->Stretch());
+    // 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()) {
@@ -1145,21 +1150,21 @@ gfxFT2FontList::AddFaceToList(const nsCS
         fe->mStandardFace = (aStdFile == kStandard);
         family->AddFontEntry(fe);
 
         fe->CheckForBrokenFont(family);
 
         AppendToFaceList(aFaceList, name, fe);
         if (LOG_ENABLED()) {
             LOG(("(fontinit) added (%s) to family (%s)"
-                 " with style: %s weight: %g stretch: %d",
+                 " with style: %s weight: %g stretch: %g%%",
                  NS_ConvertUTF16toUTF8(fe->Name()).get(),
                  NS_ConvertUTF16toUTF8(family->Name()).get(),
                  fe->IsItalic() ? "italic" : "normal",
-                 fe->Weight().ToFloat(), fe->Stretch()));
+                 fe->Weight().ToFloat(), fe->Stretch().Percentage()));
         }
     }
 }
 
 void
 gfxFT2FontList::AppendFacesFromOmnijarEntry(nsZipArchive* aArchive,
                                             const nsCString& aEntryName,
                                             FontNameCache *aCache,
@@ -1460,18 +1465,18 @@ gfxFT2FontList::InitFontListForPlatform(
 }
 
 // called for each family name, based on the assumption that the
 // first part of the full name is the family name
 
 gfxFontEntry*
 gfxFT2FontList::LookupLocalFont(const nsAString& aFontName,
                                 FontWeight aWeight,
-                                uint16_t aStretch,
-                                uint8_t aStyle)
+                                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,18 +1547,18 @@ gfxFT2FontList::GetDefaultFontForPlatfor
 #endif
     /* TODO: what about Qt or other platforms that may use this? */
     return ff;
 }
 
 gfxFontEntry*
 gfxFT2FontList::MakePlatformFont(const nsAString& aFontName,
                                  FontWeight aWeight,
-                                 uint16_t aStretch,
-                                 uint8_t aStyle,
+                                 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, aWeight, aStretch,
                                          aStyle, aFontData, aLength);
--- a/gfx/thebes/gfxFT2FontList.h
+++ b/gfx/thebes/gfxFT2FontList.h
@@ -39,18 +39,18 @@ public:
     const nsString& GetName() const {
         return Name();
     }
 
     // create a font entry for a downloaded font
     static FT2FontEntry* 
     CreateFontEntry(const nsAString& aFontName,
                     FontWeight aWeight,
-                    uint16_t aStretch,
-                    uint8_t aStyle,
+                    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);
@@ -118,23 +118,23 @@ public:
 class gfxFT2FontList : public gfxPlatformFontList
 {
 public:
     gfxFT2FontList();
     virtual ~gfxFT2FontList();
 
     virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
                                           FontWeight aWeight,
-                                          uint16_t aStretch,
-                                          uint8_t aStyle) override;
+                                          FontStretch aStretch,
+                                          FontSlantStyle aStyle) override;
 
     virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
                                            FontWeight aWeight,
-                                           uint16_t aStretch,
-                                           uint8_t aStyle,
+                                           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
@@ -191,63 +191,64 @@ MapFcWeight(int aFcWeight)
   if (aFcWeight <= FC_WEIGHT_BLACK) {
     return FontWeight(900);
   }
 
   // including FC_WEIGHT_EXTRABLACK
   return FontWeight(901);
 }
 
-static int16_t
+// TODO(emilio, jfkthame): I think this can now be more fine-grained.
+static FontStretch
 MapFcWidth(int aFcWidth)
 {
     if (aFcWidth <= (FC_WIDTH_ULTRACONDENSED + FC_WIDTH_EXTRACONDENSED) / 2) {
-        return NS_FONT_STRETCH_ULTRA_CONDENSED;
+        return FontStretch::UltraCondensed();
     }
     if (aFcWidth <= (FC_WIDTH_EXTRACONDENSED + FC_WIDTH_CONDENSED) / 2) {
-        return NS_FONT_STRETCH_EXTRA_CONDENSED;
+        return FontStretch::ExtraCondensed();
     }
     if (aFcWidth <= (FC_WIDTH_CONDENSED + FC_WIDTH_SEMICONDENSED) / 2) {
-        return NS_FONT_STRETCH_CONDENSED;
+        return FontStretch::Condensed();
     }
     if (aFcWidth <= (FC_WIDTH_SEMICONDENSED + FC_WIDTH_NORMAL) / 2) {
-        return NS_FONT_STRETCH_SEMI_CONDENSED;
+        return FontStretch::SemiCondensed();
     }
     if (aFcWidth <= (FC_WIDTH_NORMAL + FC_WIDTH_SEMIEXPANDED) / 2) {
-        return NS_FONT_STRETCH_NORMAL;
+        return FontStretch::Normal();
     }
     if (aFcWidth <= (FC_WIDTH_SEMIEXPANDED + FC_WIDTH_EXPANDED) / 2) {
-        return NS_FONT_STRETCH_SEMI_EXPANDED;
+        return FontStretch::SemiExpanded();
     }
     if (aFcWidth <= (FC_WIDTH_EXPANDED + FC_WIDTH_EXTRAEXPANDED) / 2) {
-        return NS_FONT_STRETCH_EXPANDED;
+        return FontStretch::Expanded();
     }
     if (aFcWidth <= (FC_WIDTH_EXTRAEXPANDED + FC_WIDTH_ULTRAEXPANDED) / 2) {
-        return NS_FONT_STRETCH_EXTRA_EXPANDED;
+        return FontStretch::ExtraExpanded();
     }
-    return NS_FONT_STRETCH_ULTRA_EXPANDED;
+    return FontStretch::UltraExpanded();
 }
 
 gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString& aFaceName,
                                                FcPattern* aFontPattern,
                                                bool aIgnoreFcCharmap)
         : gfxFontEntry(aFaceName), mFontPattern(aFontPattern),
           mFTFace(nullptr), mFTFaceInitialized(false),
           mIgnoreFcCharmap(aIgnoreFcCharmap),
           mAspect(0.0), mFontData(nullptr), mLength(0)
 {
     // italic
     int slant;
     if (FcPatternGetInteger(aFontPattern, FC_SLANT, 0, &slant) != FcResultMatch) {
         slant = FC_SLANT_ROMAN;
     }
     if (slant == FC_SLANT_OBLIQUE) {
-        mStyle = NS_FONT_STYLE_OBLIQUE;
+        mStyle = FontSlantStyle::Oblique();
     } else if (slant > 0) {
-        mStyle = NS_FONT_STYLE_ITALIC;
+        mStyle = FontSlantStyle::Italic();
     }
 
     // weight
     int weight;
     if (FcPatternGetInteger(aFontPattern, FC_WEIGHT, 0, &weight) != FcResultMatch) {
         weight = FC_WEIGHT_REGULAR;
     }
     mWeight = MapFcWeight(weight);
@@ -307,18 +308,18 @@ CreateFaceForPattern(FcPattern* aPattern
     if (FcPatternGetInteger(aPattern, FC_INDEX, 0, &index) != FcResultMatch) {
         index = 0; // default to 0 if not found in pattern
     }
     return Factory::NewFTFace(nullptr, ToCharPtr(filename), index);
 }
 
 gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString& aFaceName,
                                                FontWeight aWeight,
-                                               uint16_t aStretch,
-                                               uint8_t aStyle,
+                                               FontStretch aStretch,
+                                               FontSlantStyle aStyle,
                                                const uint8_t *aData,
                                                uint32_t aLength,
                                                FT_Face aFace)
     : gfxFontEntry(aFaceName),
       mFTFace(aFace), mFTFaceInitialized(true),
       mIgnoreFcCharmap(true),
       mAspect(0.0), mFontData(aData), mLength(aLength)
 {
@@ -330,18 +331,18 @@ gfxFontconfigFontEntry::gfxFontconfigFon
     mFontPattern = CreatePatternForFace(mFTFace);
 
     mUserFontData = new FTUserFontData(mFTFace, mFontData);
 }
 
 gfxFontconfigFontEntry::gfxFontconfigFontEntry(const nsAString& aFaceName,
                                                FcPattern* aFontPattern,
                                                FontWeight aWeight,
-                                               uint16_t aStretch,
-                                               uint8_t aStyle)
+                                               FontStretch aStretch,
+                                               FontSlantStyle aStyle)
         : gfxFontEntry(aFaceName), mFontPattern(aFontPattern),
           mFTFace(nullptr), mFTFaceInitialized(false),
           mAspect(0.0), mFontData(nullptr), mLength(0)
 {
     mWeight = aWeight;
     mStyle = aStyle;
     mStretch = aStretch;
     mIsLocalUserFont = true;
@@ -749,17 +750,17 @@ gfxFontconfigFontEntry::CreateScaledFont
                                          bool aNeedsBold)
 {
     if (aNeedsBold) {
         FcPatternAddBool(aRenderPattern, FC_EMBOLDEN, FcTrue);
     }
 
     // will synthetic oblique be applied using a transform?
     bool needsOblique = IsUpright() &&
-                        aStyle->style != NS_FONT_STYLE_NORMAL &&
+                        aStyle->style != FontSlantStyle::Normal() &&
                         aStyle->allowSyntheticStyle;
 
     if (needsOblique) {
         // disable embedded bitmaps (mimics behavior in 90-synthetic.conf)
         FcPatternDel(aRenderPattern, FC_EMBEDDED_BITMAP);
         FcPatternAddBool(aRenderPattern, FC_EMBEDDED_BITMAP, FcFalse);
     }
 
@@ -1197,23 +1198,24 @@ gfxFontconfigFontFamily::FindStyleVariat
         AddFontEntry(fontEntry);
 
         if (fontEntry->IsNormalStyle()) {
             numRegularFaces++;
         }
 
         if (LOG_FONTLIST_ENABLED()) {
             LOG_FONTLIST(("(fontlist) added (%s) to family (%s)"
-                 " with style: %s weight: %g stretch: %d"
+                 " with style: %s weight: %g stretch: %g%%"
                  " psname: %s fullname: %s",
                  NS_ConvertUTF16toUTF8(fontEntry->Name()).get(),
                  NS_ConvertUTF16toUTF8(Name()).get(),
                  (fontEntry->IsItalic()) ?
                   "italic" : (fontEntry->IsOblique() ? "oblique" : "normal"),
-                 fontEntry->Weight().ToFloat(), fontEntry->Stretch(),
+                 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) {
@@ -1853,18 +1855,18 @@ gfxFcPlatformFontList::GetDefaultFontFor
         return (*prefFonts)[0];
     }
     return nullptr;
 }
 
 gfxFontEntry*
 gfxFcPlatformFontList::LookupLocalFont(const nsAString& aFontName,
                                        FontWeight aWeight,
-                                       uint16_t aStretch,
-                                       uint8_t aStyle)
+                                       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;
@@ -1872,18 +1874,18 @@ gfxFcPlatformFontList::LookupLocalFont(c
 
     return new gfxFontconfigFontEntry(aFontName, fontPattern,
                                       aWeight, aStretch, aStyle);
 }
 
 gfxFontEntry*
 gfxFcPlatformFontList::MakePlatformFont(const nsAString& aFontName,
                                         FontWeight aWeight,
-                                        uint16_t aStretch,
-                                        uint8_t aStyle,
+                                        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;
     }
--- a/gfx/thebes/gfxFcPlatformFontList.h
+++ b/gfx/thebes/gfxFcPlatformFontList.h
@@ -90,28 +90,28 @@ public:
     explicit gfxFontconfigFontEntry(const nsAString& aFaceName,
                                     FcPattern* aFontPattern,
                                     bool aIgnoreFcCharmap);
 
     // used for data fonts where the fontentry takes ownership
     // of the font data and the FT_Face
     explicit gfxFontconfigFontEntry(const nsAString& aFaceName,
                                     FontWeight aWeight,
-                                    uint16_t aStretch,
-                                    uint8_t aStyle,
+                                    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,
                                     FontWeight aWeight,
-                                    uint16_t aStretch,
-                                    uint8_t aStyle);
+                                    FontStretch aStretch,
+                                    FontSlantStyle aStyle);
 
     gfxFontEntry* Clone() const override;
 
     FcPattern* GetPattern() { return mFontPattern; }
 
     nsresult ReadCMAP(FontInfoData *aFontInfoData = nullptr) override;
     bool TestCharacterMap(uint32_t aCh) override;
 
@@ -285,23 +285,24 @@ public:
                      nsTArray<nsString>& aListOfFonts) override;
 
     void ReadSystemFontList(
         InfallibleTArray<mozilla::dom::SystemFontListEntry>* retValue);
 
     gfxFontEntry*
     LookupLocalFont(const nsAString& aFontName,
                     FontWeight aWeight,
-                    uint16_t aStretch, uint8_t aStyle) override;
+                    FontStretch aStretch,
+                    FontSlantStyle aStyle) override;
 
     gfxFontEntry*
     MakePlatformFont(const nsAString& aFontName,
                      FontWeight aWeight,
-                     uint16_t aStretch,
-                     uint8_t aStyle,
+                     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/gfxFont.cpp
+++ b/gfx/thebes/gfxFont.cpp
@@ -2670,17 +2670,17 @@ gfxFont::Measure(const gfxTextRun *aText
         if (isRTL) {
             metrics.mBoundingBox -= gfxPoint(x, 0);
         }
     }
 
     // If the font may be rendered with a fake-italic effect, we need to allow
     // for the top-right of the glyphs being skewed to the right, and the
     // bottom-left being skewed further left.
-    if (mStyle.style != NS_FONT_STYLE_NORMAL &&
+    if (mStyle.style != FontSlantStyle::Normal() &&
         mFontEntry->IsUpright() &&
         mStyle.allowSyntheticStyle) {
         gfxFloat extendLeftEdge =
             ceil(OBLIQUE_SKEW_FACTOR * metrics.mBoundingBox.YMost());
         gfxFloat extendRightEdge =
             ceil(OBLIQUE_SKEW_FACTOR * -metrics.mBoundingBox.Y());
         metrics.mBoundingBox.SetWidth(metrics.mBoundingBox.Width() + extendLeftEdge + extendRightEdge);
         metrics.mBoundingBox.MoveByX(-extendLeftEdge);
@@ -4107,30 +4107,30 @@ gfxFont::RemoveGlyphChangeObserver(Glyph
 #define DEFAULT_PIXEL_FONT_SIZE 16.0f
 
 gfxFontStyle::gfxFontStyle() :
     language(nsGkAtoms::x_western),
     size(DEFAULT_PIXEL_FONT_SIZE), sizeAdjust(-1.0f), baselineOffset(0.0f),
     languageOverride(NO_FONT_LANGUAGE_OVERRIDE),
     fontSmoothingBackgroundColor(NS_RGBA(0, 0, 0, 0)),
     weight(FontWeight::Normal()),
-    stretch(NS_FONT_STRETCH_NORMAL),
-    style(NS_FONT_STYLE_NORMAL),
+    stretch(FontStretch::Normal()),
+    style(FontSlantStyle::Normal()),
     variantCaps(NS_FONT_VARIANT_CAPS_NORMAL),
     variantSubSuper(NS_FONT_VARIANT_POSITION_NORMAL),
     systemFont(true), printerFont(false), useGrayscaleAntialiasing(false),
     allowSyntheticWeight(true), allowSyntheticStyle(true),
     noFallbackVariantFeatures(true),
     explicitLanguage(false)
 {
 }
 
-gfxFontStyle::gfxFontStyle(uint8_t aStyle,
+gfxFontStyle::gfxFontStyle(FontSlantStyle aStyle,
                            FontWeight aWeight,
-                           uint16_t aStretch,
+                           FontStretch aStretch,
                            gfxFloat aSize,
                            nsAtom *aLanguage, bool aExplicitLanguage,
                            float aSizeAdjust, bool aSystemFont,
                            bool aPrinterFont,
                            bool aAllowWeightSynthesis,
                            bool aAllowStyleSynthesis,
                            uint32_t aLanguageOverride):
     language(aLanguage),
@@ -4168,16 +4168,30 @@ gfxFontStyle::gfxFontStyle(uint8_t aStyl
     }
 
     if (!language) {
         NS_WARNING("null language");
         language = nsGkAtoms::x_western;
     }
 }
 
+PLDHashNumber
+gfxFontStyle::Hash() const
+{
+    return mozilla::HashGeneric(systemFont, style.ForHash(),
+                                stretch.ForHash(), weight.ForHash(),
+                                size, sizeAdjust,
+                                nsRefPtrHashKey<nsAtom>::HashKey(language));
+    /* XXX
+    return (style + (systemFont << 7) + (weight.ForHash() << 8) +
+            uint32_t(size*1000) + int32_t(sizeAdjust*1000)) ^
+            nsRefPtrHashKey<nsAtom>::HashKey(language);
+    */
+}
+
 void
 gfxFontStyle::AdjustForSubSuperscript(int32_t aAppUnitsPerDevPixel)
 {
     NS_PRECONDITION(variantSubSuper != NS_FONT_VARIANT_POSITION_NORMAL &&
                     baselineOffset == 0,
                     "can't adjust this style for sub/superscript");
 
     // calculate the baseline offset (before changing the size)
--- a/gfx/thebes/gfxFont.h
+++ b/gfx/thebes/gfxFont.h
@@ -71,20 +71,22 @@ class gfxMathTable;
 
 struct gfxTextRunDrawCallbacks;
 
 namespace mozilla {
 class SVGContextPaint;
 } // namespace mozilla
 
 struct gfxFontStyle {
+    typedef mozilla::FontStretch FontStretch;
+    typedef mozilla::FontSlantStyle FontSlantStyle;
     typedef mozilla::FontWeight FontWeight;
 
     gfxFontStyle();
-    gfxFontStyle(uint8_t aStyle, FontWeight aWeight, uint16_t aStretch,
+    gfxFontStyle(FontSlantStyle aStyle, FontWeight aWeight, FontStretch aStretch,
                  gfxFloat aSize, nsAtom *aLanguage, bool aExplicitLanguage,
                  float aSizeAdjust, bool aSystemFont,
                  bool aPrinterFont,
                  bool aWeightSynthesis, bool aStyleSynthesis,
                  uint32_t aLanguageOverride);
 
     // the language (may be an internal langGroup code rather than an actual
     // language code) specified in the document or element's lang property,
@@ -137,21 +139,21 @@ struct gfxFontStyle {
 
     // The estimated background color behind the text. Enables a special
     // rendering mode when NS_GET_A(.) > 0. Only used for text in the chrome.
     nscolor fontSmoothingBackgroundColor;
 
     // The weight of the font: 100, 200, ... 900.
     FontWeight weight;
 
-    // The stretch of the font (NS_FONT_STRETCH_*, see gfxFontConstants.h).
-    uint8_t stretch;
+    // The stretch of the font
+    FontStretch stretch;
 
-    // The style of font (normal, italic, oblique)
-    uint8_t style;
+    // The style of font
+    FontSlantStyle style;
 
     // caps variant (small-caps, petite-caps, etc.)
     uint8_t variantCaps;
 
     // sub/superscript variant
     uint8_t variantSubSuper;
 
     // Say that this font is a system font and therefore does not
@@ -180,21 +182,17 @@ struct gfxFontStyle {
     // Return the final adjusted font size for the given aspect ratio.
     // Not meant to be called when sizeAdjust = -1.0.
     gfxFloat GetAdjustedSize(gfxFloat aspect) const {
         NS_ASSERTION(sizeAdjust >= 0.0, "Not meant to be called when sizeAdjust = -1.0");
         gfxFloat adjustedSize = std::max(NS_round(size*(sizeAdjust/aspect)), 1.0);
         return std::min(adjustedSize, FONT_MAX_SIZE);
     }
 
-    PLDHashNumber Hash() const {
-        return (style + (systemFont << 7) + (weight.ForHash() << 8) +
-            uint32_t(size*1000) + int32_t(sizeAdjust*1000)) ^
-            nsRefPtrHashKey<nsAtom>::HashKey(language);
-    }
+    PLDHashNumber Hash() const;
 
     // Adjust this style to simulate sub/superscript (as requested in the
     // variantSubSuper field) using size and baselineOffset instead.
     void AdjustForSubSuperscript(int32_t aAppUnitsPerDevPixel);
 
     bool Equals(const gfxFontStyle& other) const {
         return
             (*reinterpret_cast<const uint64_t*>(&size) ==
@@ -1448,16 +1446,18 @@ class gfxFont {
 protected:
     typedef mozilla::gfx::DrawTarget DrawTarget;
     typedef mozilla::unicode::Script Script;
     typedef mozilla::SVGContextPaint SVGContextPaint;
 
     typedef gfxFontShaper::RoundingFlags RoundingFlags;
 
 public:
+    typedef mozilla::FontSlantStyle FontSlantStyle;
+
     nsrefcnt AddRef(void) {
         NS_PRECONDITION(int32_t(mRefCnt) >= 0, "illegal refcnt");
         if (mExpirationState.IsTracked()) {
             gfxFontCache::GetCache()->RemoveObject(this);
         }
         ++mRefCnt;
         NS_LOG_ADDREF(this, mRefCnt, "gfxFont", sizeof(*this));
         return mRefCnt;
@@ -1808,17 +1808,17 @@ public:
     virtual bool SetupCairoFont(DrawTarget* aDrawTarget) = 0;
 
     virtual bool AllowSubpixelAA() { return true; }
 
     bool IsSyntheticBold() { return mApplySyntheticBold; }
 
     bool IsSyntheticOblique() {
         return mFontEntry->IsUpright() &&
-               mStyle.style != NS_FONT_STYLE_NORMAL &&
+               mStyle.style != FontSlantStyle::Normal() &&
                mStyle.allowSyntheticStyle;
     }
 
     // Amount by which synthetic bold "fattens" the glyphs:
     // For size S up to a threshold size T, we use (0.25 + 3S / 4T),
     // so that the result ranges from 0.25 to 1.0; thereafter,
     // simply use (S / T).
     gfxFloat GetSyntheticBoldOffset() {
--- a/gfx/thebes/gfxFontEntry.cpp
+++ b/gfx/thebes/gfxFontEntry.cpp
@@ -53,17 +53,17 @@ gfxCharacterMap::NotifyReleased()
     gfxPlatformFontList *fontlist = gfxPlatformFontList::PlatformFontList();
     if (mShared) {
         fontlist->RemoveCmap(this);
     }
     delete this;
 }
 
 gfxFontEntry::gfxFontEntry() :
-    mStyle(NS_FONT_STYLE_NORMAL), mFixedPitch(false),
+    mFixedPitch(false),
     mIsBadUnderlineFont(false),
     mIsUserFontContainer(false),
     mIsDataUserFont(false),
     mIsLocalUserFont(false),
     mStandardFace(false),
     mIgnoreGDEF(false),
     mIgnoreGSUB(false),
     mSVGInitialized(false),
@@ -75,33 +75,35 @@ gfxFontEntry::gfxFontEntry() :
     mGraphiteSpaceContextualsInitialized(false),
     mHasGraphiteSpaceContextuals(false),
     mSpaceGlyphIsInvisible(false),
     mSpaceGlyphIsInvisibleInitialized(false),
     mCheckedForGraphiteTables(false),
     mHasCmapTable(false),
     mGrFaceInitialized(false),
     mCheckedForColorGlyph(false),
-    mWeight(500), mStretch(NS_FONT_STRETCH_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),
     mComputedSizeOfUserFont(0)
 {
     memset(&mDefaultSubSpaceFeatures, 0, sizeof(mDefaultSubSpaceFeatures));
     memset(&mNonDefaultSubSpaceFeatures, 0, sizeof(mNonDefaultSubSpaceFeatures));
 }
 
 gfxFontEntry::gfxFontEntry(const nsAString& aName, bool aIsStandardFace) :
-    mName(aName), mStyle(NS_FONT_STYLE_NORMAL), mFixedPitch(false),
+    mName(aName), mFixedPitch(false),
     mIsBadUnderlineFont(false),
     mIsUserFontContainer(false),
     mIsDataUserFont(false),
     mIsLocalUserFont(false), mStandardFace(aIsStandardFace),
     mIgnoreGDEF(false),
     mIgnoreGSUB(false),
     mSVGInitialized(false),
     mHasSpaceFeaturesInitialized(false),
@@ -112,17 +114,19 @@ gfxFontEntry::gfxFontEntry(const nsAStri
     mGraphiteSpaceContextualsInitialized(false),
     mHasGraphiteSpaceContextuals(false),
     mSpaceGlyphIsInvisible(false),
     mSpaceGlyphIsInvisibleInitialized(false),
     mCheckedForGraphiteTables(false),
     mHasCmapTable(false),
     mGrFaceInitialized(false),
     mCheckedForColorGlyph(false),
-    mWeight(500), mStretch(NS_FONT_STRETCH_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),
@@ -1173,49 +1177,49 @@ gfxFontFamily::FindFontForStyle(const gf
     }
     return nullptr;
 }
 
 #define STYLE_SHIFT 2 // number of bits to contain style distance
 
 // style distance ==> [0,2]
 static inline uint32_t
-StyleDistance(uint32_t aFontStyle, uint32_t aTargetStyle)
+StyleDistance(FontSlantStyle aFontStyle, FontSlantStyle aTargetStyle)
 {
     if (aFontStyle == aTargetStyle) {
         return 0; // styles match exactly ==> 0
     }
-    if (aFontStyle == NS_FONT_STYLE_NORMAL ||
-        aTargetStyle == NS_FONT_STYLE_NORMAL) {
+    if (aFontStyle == FontSlantStyle::Normal() ||
+        aTargetStyle == FontSlantStyle::Normal()) {
         return 2; // one is normal (but not the other) ==> 2
     }
     return 1; // neither is normal; must be italic vs oblique ==> 1
 }
 
-#define REVERSE_STRETCH_DISTANCE 200
+#define REVERSE_STRETCH_DISTANCE 200.0f
 
 // stretch distance ==> [0,350]
 static inline uint32_t
-StretchDistance(int32_t aFontStretch, int32_t aTargetStretch)
+StretchDistance(FontStretch aFontStretch, FontStretch aTargetStretch)
 {
-    int32_t distance = 0;
+    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 > 100) {
+        if (aTargetStretch > FontStretch::Normal()) {
             distance = (aFontStretch - aTargetStretch);
         } else {
             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 150) by adding an extra 200 to the absolute value
-        if (distance < 0) {
+        if (distance < 0.0f) {
             distance = -distance + REVERSE_STRETCH_DISTANCE;
         }
     }
     return uint32_t(distance);
 }
 
 // CSS currently limits font weights to multiples of 100 but the weight
 // matching code below does not assume this.
@@ -1330,17 +1334,17 @@ gfxFontFamily::FindAllFontsForStyle(cons
     // We can then pick the required entry based on whether the request is for
     // bold or non-bold, italic or non-italic, without running the more complex
     // matching algorithm used for larger families with many weights and/or widths.
 
     if (mIsSimpleFamily) {
         // Family has no more than the "standard" 4 faces, at fixed indexes;
         // calculate which one we want.
         // Note that we cannot simply return it as not all 4 faces are necessarily present.
-        bool wantItalic = (aFontStyle.style != NS_FONT_STYLE_NORMAL);
+        bool wantItalic = !aFontStyle.style.IsNormal();
         uint8_t faceIndex = (wantItalic ? kItalicMask : 0) |
                             (wantBold ? kBoldMask : 0);
 
         // if the desired style is available, return it directly
         fe = mAvailableFonts[faceIndex];
         if (fe) {
             // no need to set aNeedsSyntheticBold here as we matched the boldness request
             aFontEntryList.AppendElement(fe);
@@ -1430,17 +1434,17 @@ gfxFontFamily::CheckForSimpleFamily()
                 // if none then the family is unusable anyway
     }
 
     if (count == 1) {
         mIsSimpleFamily = true;
         return;
     }
 
-    uint16_t firstStretch = mAvailableFonts[0]->Stretch();
+    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;
         }
@@ -1493,17 +1497,17 @@ void gfxFontFamily::LocalizedName(nsAStr
 
 // metric for how close a given font matches a style
 static int32_t
 CalcStyleMatch(gfxFontEntry *aFontEntry, const gfxFontStyle *aStyle)
 {
     int32_t rank = 0;
     if (aStyle) {
          // italics
-         bool wantUpright = (aStyle->style == NS_FONT_STYLE_NORMAL);
+         bool wantUpright = aStyle->style.IsNormal();
          if (aFontEntry->IsUpright() == wantUpright) {
              rank += 10;
          }
 
         // measure of closeness of weight to the desired value
         rank += 9 - Abs((aFontEntry->Weight() - aStyle->weight) / 100.0f);
     } else {
         // if no font to match, prefer non-bold, non-italic fonts
--- a/gfx/thebes/gfxFontEntry.h
+++ b/gfx/thebes/gfxFontEntry.h
@@ -105,19 +105,21 @@ private:
 struct gfxFontFeatureInfo {
     uint32_t mTag;
     uint32_t mScript;
     uint32_t mLangSys;
 };
 
 class gfxFontEntry {
 public:
-    typedef mozilla::FontWeight FontWeight;
     typedef mozilla::gfx::DrawTarget DrawTarget;
     typedef mozilla::unicode::Script Script;
+    typedef mozilla::FontWeight FontWeight;
+    typedef mozilla::FontSlantStyle FontSlantStyle;
+    typedef mozilla::FontStretch FontStretch;
 
     // 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).
@@ -137,39 +139,39 @@ public:
     // they are intended only for the font-inspection API, not for
     // perf-critical layout/drawing work.
 
     // The "real" name of the face, if available from the font resource;
     // returns Name() if nothing better is available.
     virtual nsString RealFaceName();
 
     FontWeight Weight() const { return mWeight; }
-    uint16_t Stretch() const { return mStretch; }
+    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 mStyle == NS_FONT_STYLE_ITALIC; }
-    bool IsOblique() const { return mStyle == NS_FONT_STYLE_OBLIQUE; }
-    bool IsUpright() const { return mStyle == NS_FONT_STYLE_NORMAL; }
+    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() == FontWeight::Normal() &&
-               Stretch() == NS_FONT_STRETCH_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
@@ -369,17 +371,16 @@ public:
     }
 
     // Get the font's list of features (if any) for DevTools support.
     void GetFeatureInfo(nsTArray<gfxFontFeatureInfo>& aFeatureInfo);
 
     nsString         mName;
     nsString         mFamilyName;
 
-    uint8_t          mStyle       : 2; // italic/oblique
     bool             mFixedPitch  : 1;
     bool             mIsBadUnderlineFont : 1;
     bool             mIsUserFontContainer : 1; // userfont entry
     bool             mIsDataUserFont : 1;      // platform font entry (data)
     bool             mIsLocalUserFont : 1;     // platform font entry (local)
     bool             mStandardFace : 1;
     bool             mIgnoreGDEF  : 1;
     bool             mIgnoreGSUB  : 1;
@@ -399,18 +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];
 
-    FontWeight       mWeight;
-    uint16_t         mStretch;
+    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;
--- a/gfx/thebes/gfxGDIFontList.cpp
+++ b/gfx/thebes/gfxGDIFontList.cpp
@@ -110,19 +110,19 @@ FontTypeToOutPrecision(uint8_t fontType)
 /***************************************************************
  *
  * GDIFontEntry
  *
  */
 
 GDIFontEntry::GDIFontEntry(const nsAString& aFaceName,
                            gfxWindowsFontType aFontType,
-                           uint8_t aStyle,
+                           FontSlantStyle aStyle,
                            FontWeight aWeight,
-                           uint16_t aStretch,
+                           FontStretch aStretch,
                            gfxUserFontData *aUserFontData)
     : gfxFontEntry(aFaceName),
       mFontType(aFontType),
       mForceGDI(false),
       mUnicodeRanges()
 {
     mUserFontData.reset(aUserFontData);
     mStyle = aStyle;
@@ -298,17 +298,17 @@ GDIFontEntry::TestCharacterMap(uint32_t 
 
     if (mCharacterMap->mBuildOnTheFly) {
         if (aCh > 0xFFFF)
             return false;
 
         // previous code was using the group style
         gfxFontStyle fakeStyle;
         if (!IsUpright()) {
-            fakeStyle.style = NS_FONT_STYLE_ITALIC;
+            fakeStyle.style = FontSlantStyle::Italic();
         }
         fakeStyle.weight = mWeight;
 
         RefPtr<gfxFont> tempFont = FindOrMakeFont(&fakeStyle, false);
         if (!tempFont || !tempFont->Valid())
             return false;
         gfxGDIFont *font = static_cast<gfxGDIFont*>(tempFont.get());
 
@@ -389,19 +389,19 @@ GDIFontEntry::InitLogFont(const nsAStrin
     int len = std::min<int>(aName.Length(), LF_FACESIZE - 1);
     memcpy(&mLogFont.lfFaceName, aName.BeginReading(), len * sizeof(char16_t));
     mLogFont.lfFaceName[len] = '\0';
 }
 
 GDIFontEntry* 
 GDIFontEntry::CreateFontEntry(const nsAString& aName,
                               gfxWindowsFontType aFontType,
-                              uint8_t aStyle,
+                              FontSlantStyle aStyle,
                               FontWeight aWeight,
-                              uint16_t aStretch,
+                              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;
@@ -475,21 +475,22 @@ GDIFontFamily::FamilyAddStylesProc(const
             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.
-    uint8_t italicStyle = (logFont.lfItalic == 0xFF ?
-                           NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL);
+    auto italicStyle = (logFont.lfItalic == 0xFF ?
+                           FontSlantStyle::Italic() : FontSlantStyle::Normal());
     fe = GDIFontEntry::CreateFontEntry(nsDependentString(lpelfe->elfFullName),
                                        feType, italicStyle,
-                                       FontWeight(int32_t(logFont.lfWeight)), 0,
+                                       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 &&
@@ -502,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: %d",
-             NS_ConvertUTF16toUTF8(fe->Name()).get(), 
-             NS_ConvertUTF16toUTF8(ff->Name()).get(), 
+             " with style: %s weight: %d stretch: %g%%",
+             NS_ConvertUTF16toUTF8(fe->Name()).get(),
+             NS_ConvertUTF16toUTF8(ff->Name()).get(),
              (logFont.lfItalic == 0xff) ? "italic" : "normal",
-             logFont.lfWeight, fe->Stretch()));
+             logFont.lfWeight,
+             fe->Stretch().Percentage(),
+             stretchString.get()));
     }
     return 1;
 }
 
 void
 GDIFontFamily::FindStyleVariations(FontInfoData *aFontInfoData)
 {
     if (mHasStyles)
@@ -706,18 +710,18 @@ gfxGDIFontList::EnumFontFamExProc(ENUMLO
     }
 
     return 1;
 }
 
 gfxFontEntry* 
 gfxGDIFontList::LookupLocalFont(const nsAString& aFontName,
                                 FontWeight aWeight,
-                                uint16_t aStretch,
-                                uint8_t aStyle)
+                                FontStretch aStretch,
+                                FontSlantStyle aStyle)
 {
     gfxFontEntry *lookup;
 
     lookup = LookupInFaceNameLists(aFontName);
     if (!lookup) {
         return nullptr;
     }
 
@@ -798,18 +802,18 @@ FixupSymbolEncodedFont(uint8_t* aFontDat
         }
     }
     return false;
 }
 
 gfxFontEntry*
 gfxGDIFontList::MakePlatformFont(const nsAString& aFontName,
                                  FontWeight aWeight,
-                                 uint16_t aStretch,
-                                 uint8_t aStyle,
+                                 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)
--- a/gfx/thebes/gfxGDIFontList.h
+++ b/gfx/thebes/gfxGDIFontList.h
@@ -103,16 +103,18 @@ 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,
@@ -163,37 +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,
-                                         uint8_t aStyle,
+                                         FontSlantStyle aStyle,
                                          FontWeight aWeight,
-                                         uint16_t aStretch,
+                                         FontStretch aStretch,
                                          gfxUserFontData* aUserFontData);
 
     // create a font entry for a font referenced by its fullname
     static GDIFontEntry* LoadLocalFont(const nsAString& aFontName,
                                        FontWeight aWeight,
-                                       uint16_t aStretch,
-                                       uint8_t aStyle);
+                                       FontStretch aStretch,
+                                       FontSlantStyle aStyle);
 
     gfxWindowsFontType mFontType;
     bool mForceGDI;
 
     gfxSparseBitSet mUnicodeRanges;
 
 protected:
     friend class gfxGDIFont;
 
     GDIFontEntry(const nsAString& aFaceName, gfxWindowsFontType aFontType,
-                 uint8_t aStyle, FontWeight aWeight, uint16_t 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,
@@ -315,16 +317,18 @@ 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;
@@ -334,23 +338,23 @@ public:
     bool FindAndAddFamilies(const nsAString& aFamily,
                             nsTArray<gfxFontFamily*>* aOutput,
                             FindFamiliesFlags aFlags,
                             gfxFontStyle* aStyle = nullptr,
                             gfxFloat aDevToCssSize = 1.0) override;
 
     virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
                                           FontWeight aWeight,
-                                          uint16_t aStretch,
-                                          uint8_t aStyle);
+                                          FontStretch aStretch,
+                                          FontSlantStyle aStyle);
 
     virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
                                            FontWeight aWeight,
-                                           uint16_t aStretch,
-                                           uint8_t aStyle,
+                                           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/gfxMacPlatformFontList.h
+++ b/gfx/thebes/gfxMacPlatformFontList.h
@@ -32,17 +32,17 @@ public:
     friend class gfxMacPlatformFontList;
 
     MacOSFontEntry(const nsAString& aPostscriptName, FontWeight aWeight,
                    bool aIsStandardFace = false,
                    double aSizeHint = 0.0);
 
     // for use with data fonts
     MacOSFontEntry(const nsAString& aPostscriptName, CGFontRef aFontRef,
-                   FontWeight aWeight, uint16_t aStretch, uint8_t aStyle,
+                   FontWeight aWeight, FontStretch aStretch, FontSlantStyle aStyle,
                    bool aIsDataUserFont, bool aIsLocal);
 
     virtual ~MacOSFontEntry() {
         if (mTrakTable) {
             hb_blob_destroy(mTrakTable);
         }
         ::CGFontRelease(mFontRef);
     }
@@ -127,23 +127,23 @@ public:
     gfxFontFamily* CreateFontFamily(const nsAString& aName) const override;
 
     static int32_t AppleWeightToCSSWeight(int32_t aAppleWeight);
 
     bool GetStandardFamilyName(const nsAString& aFontName, nsAString& aFamilyName) override;
 
     gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
                                   FontWeight aWeight,
-                                  uint16_t aStretch,
-                                  uint8_t aStyle) override;
+                                  FontStretch aStretch,
+                                  FontSlantStyle aStyle) override;
 
     gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
                                    FontWeight aWeight,
-                                   uint16_t aStretch,
-                                   uint8_t aStyle,
+                                   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
@@ -384,18 +384,18 @@ MacOSFontEntry::MacOSFontEntry(const nsA
       mTrakSizeTable(nullptr)
 {
     mWeight = aWeight;
 }
 
 MacOSFontEntry::MacOSFontEntry(const nsAString& aPostscriptName,
                                CGFontRef aFontRef,
                                FontWeight aWeight,
-                               uint16_t aStretch,
-                               uint8_t aStyle,
+                               FontStretch aStretch,
+                               FontSlantStyle aStyle,
                                bool aIsDataUserFont,
                                bool aIsLocalUserFont)
     : gfxFontEntry(aPostscriptName, false),
       mFontRef(NULL),
       mSizeHint(0.0),
       mFontRefInitialized(false),
       mRequiresAAT(false),
       mIsCFF(false),
@@ -907,40 +907,40 @@ gfxMacFontFamily::FindStyleVariations(Fo
             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->mStretch = NS_FONT_STRETCH_CONDENSED;
+            fontEntry->mStretch = FontStretch::Condensed();
         } else if (macTraits & NSExpandedFontMask) {
-            fontEntry->mStretch = NS_FONT_STRETCH_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->mStyle = NS_FONT_STYLE_ITALIC;
+            fontEntry->mStyle = FontSlantStyle::Italic();
         }
         if (macTraits & NSFixedPitchFontMask) {
             fontEntry->mFixedPitch = true;
         }
 
         if (LOG_FONTLIST_ENABLED()) {
             LOG_FONTLIST(("(fontlist) added (%s) to family (%s)"
-                 " with style: %s weight: %d stretch: %d"
+                 " with style: %s weight: %d stretch: %g%%"
                  " (apple-weight: %d macTraits: %8.8x)",
-                 NS_ConvertUTF16toUTF8(fontEntry->Name()).get(), 
-                 NS_ConvertUTF16toUTF8(Name()).get(), 
+                 NS_ConvertUTF16toUTF8(fontEntry->Name()).get(),
+                 NS_ConvertUTF16toUTF8(Name()).get(),
                  fontEntry->IsItalic() ? "italic" : "normal",
-                 cssWeight, fontEntry->Stretch(),
+                 cssWeight, fontEntry->Stretch().Percentage(),
                  appKitWeight, macTraits));
         }
 
         // insert into font entry array of family
         AddFontEntry(fontEntry);
     }
 
     SortAvailableFonts();
@@ -1529,18 +1529,18 @@ gfxMacPlatformFontList::AppleWeightToCSS
     else if (aAppleWeight > kAppleMaxWeight)
         aAppleWeight = kAppleMaxWeight;
     return gAppleWeightToCSSWeight[aAppleWeight];
 }
 
 gfxFontEntry*
 gfxMacPlatformFontList::LookupLocalFont(const nsAString& aFontName,
                                         FontWeight aWeight,
-                                        uint16_t aStretch,
-                                        uint8_t aStyle)
+                                        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));
@@ -1562,18 +1562,18 @@ gfxMacPlatformFontList::LookupLocalFont(
 static void ReleaseData(void *info, const void *data, size_t size)
 {
     free((void*)data);
 }
 
 gfxFontEntry*
 gfxMacPlatformFontList::MakePlatformFont(const nsAString& aFontName,
                                          FontWeight aWeight,
-                                         uint16_t aStretch,
-                                         uint8_t aStyle,
+                                         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!");
 
@@ -1698,23 +1698,23 @@ gfxMacPlatformFontList::LookupSystemFont
     NS_ASSERTION(systemFontName, "system font name not set");
 
     if (systemFontName) {
         aSystemFontName.AssignASCII(systemFontName);
     }
 
     NSFontSymbolicTraits traits = [[font fontDescriptor] symbolicTraits];
     aFontStyle.style =
-        (traits & NSFontItalicTrait) ?  NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL;
+        (traits & NSFontItalicTrait) ?  FontSlantStyle::Italic() : FontSlantStyle::Normal();
     aFontStyle.weight =
         (traits & NSFontBoldTrait) ? FontWeight::Bold() : FontWeight::Normal();
     aFontStyle.stretch =
         (traits & NSFontExpandedTrait) ?
-            NS_FONT_STRETCH_EXPANDED : (traits & NSFontCondensedTrait) ?
-                NS_FONT_STRETCH_CONDENSED : NS_FONT_STRETCH_NORMAL;
+            FontStretch::Expanded() : (traits & NSFontCondensedTrait) ?
+                FontStretch::Condensed() : FontStretch::Normal();
     // convert size from css pixels to device pixels
     aFontStyle.size = [font pointSize] * aDevPixPerCSSPixel;
     aFontStyle.systemFont = true;
 }
 
 // used to load system-wide font info on off-main thread
 class MacFontInfo : public FontInfoData {
 public:
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -1749,30 +1749,30 @@ gfxPlatform::IsFontFormatSupported(uint3
 
     // no format hint set, need to look at data
     return true;
 }
 
 gfxFontEntry*
 gfxPlatform::LookupLocalFont(const nsAString& aFontName,
                              FontWeight aWeight,
-                             uint16_t aStretch,
-                             uint8_t aStyle)
+                             FontStretch aStretch,
+                             FontSlantStyle aStyle)
 {
     return gfxPlatformFontList::PlatformFontList()->LookupLocalFont(aFontName,
                                                                     aWeight,
                                                                     aStretch,
                                                                     aStyle);
 }
 
 gfxFontEntry*
 gfxPlatform::MakePlatformFont(const nsAString& aFontName,
                               FontWeight aWeight,
-                              uint16_t aStretch,
-                              uint8_t aStyle,
+                              FontStretch aStretch,
+                              FontSlantStyle aStyle,
                               const uint8_t* aFontData,
                               uint32_t aLength)
 {
     return gfxPlatformFontList::PlatformFontList()->MakePlatformFont(aFontName,
                                                                      aWeight,
                                                                      aStretch,
                                                                      aStyle,
                                                                      aFontData,
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -154,16 +154,18 @@ struct BackendPrefsData
   uint32_t mContentBitmask = 0;
   mozilla::gfx::BackendType mContentDefault = mozilla::gfx::BackendType::NONE;
 };
 
 class gfxPlatform {
     friend class SRGBOverrideObserver;
 
 public:
+    typedef mozilla::FontStretch FontStretch;
+    typedef mozilla::FontSlantStyle FontSlantStyle;
     typedef mozilla::FontWeight FontWeight;
     typedef mozilla::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,31 +391,31 @@ public:
     /**
      * Look up a local platform font using the full font face name.
      * (Needed to support @font-face src local().)
      * Ownership of the returned gfxFontEntry is passed to the caller,
      * who must either AddRef() or delete.
      */
     virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
                                           FontWeight aWeight,
-                                          uint16_t aStretch,
-                                          uint8_t aStyle);
+                                          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.
      */
     virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
                                            FontWeight aWeight,
-                                           uint16_t aStretch,
-                                           uint8_t aStyle,
+                                           FontStretch aStretch,
+                                           FontSlantStyle aStyle,
                                            const uint8_t* aFontData,
                                            uint32_t aLength);
 
     /**
      * Whether to allow downloadable fonts via @font-face rules
      */
     bool DownloadableFontsEnabled();
 
--- a/gfx/thebes/gfxPlatformFontList.h
+++ b/gfx/thebes/gfxPlatformFontList.h
@@ -93,16 +93,18 @@ struct FontListSizes {
 
 class gfxUserFontSet;
 
 class gfxPlatformFontList : public gfxFontInfoLoader
 {
     friend class InitOtherFamilyNamesRunnable;
 
 public:
+    typedef mozilla::FontStretch FontStretch;
+    typedef mozilla::FontSlantStyle FontSlantStyle;
     typedef mozilla::FontWeight FontWeight;
     typedef mozilla::unicode::Script Script;
 
     static gfxPlatformFontList* PlatformFontList() {
         return sPlatformFontList;
     }
 
     static nsresult Init() {
@@ -184,25 +186,25 @@ public:
     // 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
     virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
                                           FontWeight aWeight,
-                                          uint16_t aStretch,
-                                          uint8_t aStyle) = 0;
+                                          FontStretch aStretch,
+                                          FontSlantStyle aStyle) = 0;
 
     // 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,
                                            FontWeight aWeight,
-                                           uint16_t aStretch,
-                                           uint8_t aStyle,
+                                           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
@@ -271,29 +271,29 @@ gfxPlatformGtk::CreateFontGroup(const Fo
 {
     return new gfxFontGroup(aFontFamilyList, aStyle, aTextPerf,
                             aUserFontSet, aDevToCssSize);
 }
 
 gfxFontEntry*
 gfxPlatformGtk::LookupLocalFont(const nsAString& aFontName,
                                 FontWeight aWeight,
-                                uint16_t aStretch,
-                                uint8_t aStyle)
+                                FontStretch aStretch,
+                                FontSlantStyle aStyle)
 {
     gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
     return pfl->LookupLocalFont(aFontName, aWeight, aStretch,
                                 aStyle);
 }
 
 gfxFontEntry*
 gfxPlatformGtk::MakePlatformFont(const nsAString& aFontName,
                                  FontWeight aWeight,
-                                 uint16_t aStretch,
-                                 uint8_t aStyle,
+                                 FontStretch aStretch,
+                                 FontSlantStyle aStyle,
                                  const uint8_t* aFontData,
                                  uint32_t aLength)
 {
     gfxPlatformFontList* pfl = gfxPlatformFontList::PlatformFontList();
     return pfl->MakePlatformFont(aFontName, aWeight, aStretch,
                                  aStyle, aFontData, aLength);
 }
 
--- a/gfx/thebes/gfxPlatformGtk.h
+++ b/gfx/thebes/gfxPlatformGtk.h
@@ -62,27 +62,27 @@ public:
                     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,
-                                          uint16_t aStretch,
-                                          uint8_t aStyle) override;
+                                          FontStretch aStretch,
+                                          FontSlantStyle aStyle) override;
 
     /**
      * Activate a platform font (needed to support @font-face src url() )
      *
      */
     virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
                                            FontWeight aWeight,
-                                           uint16_t aStretch,
-                                           uint8_t aStyle,
+                                           FontStretch aStretch,
+                                           FontSlantStyle aStyle,
                                            const uint8_t* aFontData,
                                            uint32_t aLength) override;
 
     /**
      * Calls XFlush if xrender is enabled.
      */
     virtual void FlushContentDrawing() override;
 
--- a/gfx/thebes/gfxTextRun.cpp
+++ b/gfx/thebes/gfxTextRun.cpp
@@ -14,16 +14,17 @@
 
 #include "gfxContext.h"
 #include "gfxFontConstants.h"
 #include "gfxFontMissingGlyphs.h"
 #include "gfxScriptItemizer.h"
 #include "nsUnicodeProperties.h"
 #include "nsUnicodeRange.h"
 #include "nsStyleConsts.h"
+#include "nsStyleUtil.h"
 #include "mozilla/Likely.h"
 #include "gfx2DGlue.h"
 #include "mozilla/gfx/Logging.h"        // for gfxCriticalError
 #include "mozilla/UniquePtr.h"
 #include "TextDrawTarget.h"
 
 #ifdef XP_WIN
 #include "gfxWindowsPlatform.h"
@@ -1761,21 +1762,25 @@ gfxTextRun::Dump(FILE* aOutput) {
     const GlyphRun* glyphRuns = GetGlyphRuns(&numGlyphRuns);
     for (uint32_t i = 0; i < numGlyphRuns; ++i) {
         if (i > 0) {
             fputc(',', aOutput);
         }
         gfxFont* font = glyphRuns[i].mFont;
         const gfxFontStyle* style = font->GetStyle();
         NS_ConvertUTF16toUTF8 fontName(font->GetName());
+        nsAutoString styleString;
+        nsStyleUtil::AppendFontSlantStyle(style->style, styleString);
         nsAutoCString lang;
         style->language->ToUTF8String(lang);
-        fprintf(aOutput, "%d: %s %f/%g/%d/%s", glyphRuns[i].mCharacterOffset,
+        fprintf(aOutput, "%d: %s %f/%g/%s/%s", glyphRuns[i].mCharacterOffset,
                 fontName.get(), style->size,
-                style->weight.ToFloat(), style->style, lang.get());
+                style->weight.ToFloat(),
+                NS_ConvertUTF16toUTF8(styleString).get(),
+                lang.get());
     }
     fputc(']', aOutput);
 }
 #endif
 
 gfxFontGroup::gfxFontGroup(const FontFamilyList& aFontFamilyList,
                            const gfxFontStyle *aStyle,
                            gfxTextPerfMetrics* aTextPerf,
@@ -2409,31 +2414,32 @@ gfxFontGroup::InitTextRun(DrawTarget* aD
         if (sizeof(T) == sizeof(uint8_t) && !transformedString) {
 
             if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Warning))) {
                 nsAutoCString lang;
                 mStyle.language->ToUTF8String(lang);
                 nsAutoString families;
                 mFamilyList.ToString(families);
                 nsAutoCString str((const char*)aString, aLength);
+                nsAutoString styleString;
+                nsStyleUtil::AppendFontSlantStyle(mStyle.style, styleString);
                 MOZ_LOG(log, LogLevel::Warning,\
                        ("(%s) fontgroup: [%s] default: %s lang: %s script: %d "
-                        "len %d weight: %g width: %d style: %s size: %6.2f %zu-byte "
+                        "len %d weight: %g stretch: %g%% style: %s size: %6.2f %zu-byte "
                         "TEXTRUN [%s] ENDTEXTRUN\n",
                         (mStyle.systemFont ? "textrunui" : "textrun"),
                         NS_ConvertUTF16toUTF8(families).get(),
                         (mFamilyList.GetDefaultFontType() == eFamily_serif ?
                          "serif" :
                          (mFamilyList.GetDefaultFontType() == eFamily_sans_serif ?
                           "sans-serif" : "none")),
                         lang.get(), static_cast<int>(Script::LATIN), aLength,
-                        mStyle.weight.ToFloat(), uint32_t(mStyle.stretch),
-                        (mStyle.style & NS_FONT_STYLE_ITALIC ? "italic" :
-                        (mStyle.style & NS_FONT_STYLE_OBLIQUE ? "oblique" :
-                                                                "normal")),
+                        mStyle.weight.ToFloat(),
+                        mStyle.stretch.Percentage(),
+                        NS_ConvertUTF16toUTF8(styleString).get(),
                         mStyle.size,
                         sizeof(T),
                         str.get()));
             }
 
             // the text is still purely 8-bit; bypass the script-run itemizer
             // and treat it as a single Latin run
             InitScriptRun(aDrawTarget, aTextRun, aString,
@@ -2456,32 +2462,33 @@ gfxFontGroup::InitTextRun(DrawTarget* aD
             Script runScript = Script::LATIN;
             while (scriptRuns.Next(runStart, runLimit, runScript)) {
 
                 if (MOZ_UNLIKELY(MOZ_LOG_TEST(log, LogLevel::Warning))) {
                     nsAutoCString lang;
                     mStyle.language->ToUTF8String(lang);
                     nsAutoString families;
                     mFamilyList.ToString(families);
+                    nsAutoString styleString;
+                    nsStyleUtil::AppendFontSlantStyle(mStyle.style, styleString);
                     uint32_t runLen = runLimit - runStart;
                     MOZ_LOG(log, LogLevel::Warning,\
                            ("(%s) fontgroup: [%s] default: %s lang: %s script: %d "
-                            "len %d weight: %g width: %d style: %s size: %6.2f "
+                            "len %d weight: %g stretch: %g%% style: %s size: %6.2f "
                             "%zu-byte TEXTRUN [%s] ENDTEXTRUN\n",
                             (mStyle.systemFont ? "textrunui" : "textrun"),
                             NS_ConvertUTF16toUTF8(families).get(),
                             (mFamilyList.GetDefaultFontType() == eFamily_serif ?
                              "serif" :
                              (mFamilyList.GetDefaultFontType() == eFamily_sans_serif ?
                               "sans-serif" : "none")),
                             lang.get(), static_cast<int>(runScript), runLen,
-                            mStyle.weight.ToFloat(), uint32_t(mStyle.stretch),
-                            (mStyle.style & NS_FONT_STYLE_ITALIC ? "italic" :
-                            (mStyle.style & NS_FONT_STYLE_OBLIQUE ? "oblique" :
-                                                                    "normal")),
+                            mStyle.weight.ToFloat(),
+                            mStyle.stretch.Percentage(),
+                            NS_ConvertUTF16toUTF8(styleString).get(),
                             mStyle.size,
                             sizeof(T),
                             NS_ConvertUTF16toUTF8(textPtr + runStart, runLen).get()));
                 }
 
                 InitScriptRun(aDrawTarget, aTextRun, textPtr + runStart,
                               runStart, runLimit - runStart, runScript, aMFR);
             }
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -101,18 +101,18 @@ private:
     size_t       mLength;
     const size_t mLimit;
     off_t        mOff;
 };
 
 gfxUserFontEntry::gfxUserFontEntry(gfxUserFontSet* aFontSet,
              const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
              FontWeight aWeight,
-             uint32_t aStretch,
-             uint8_t aStyle,
+             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),
@@ -141,18 +141,18 @@ gfxUserFontEntry::~gfxUserFontEntry()
     // traversal, since PostTraversalTask objects can hold raw pointers to
     // gfxUserFontEntry objects.
     MOZ_ASSERT(!ServoStyleSet::IsInServoTraversal());
 }
 
 bool
 gfxUserFontEntry::Matches(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                           FontWeight aWeight,
-                          uint32_t aStretch,
-                          uint8_t aStyle,
+                          FontStretch aStretch,
+                          FontSlantStyle aStyle,
                           const nsTArray<gfxFontFeature>& aFeatureSettings,
                           const nsTArray<gfxFontVariation>& aVariationSettings,
                           uint32_t aLanguageOverride,
                           gfxCharacterMap* aUnicodeRanges,
                           uint8_t aFontDisplay)
 {
     return mWeight == aWeight &&
            mStretch == aStretch &&
@@ -932,18 +932,18 @@ gfxUserFontSet::~gfxUserFontSet()
     }
 }
 
 already_AddRefed<gfxUserFontEntry>
 gfxUserFontSet::FindOrCreateUserFontEntry(
                                const nsAString& aFamilyName,
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                                FontWeight aWeight,
-                               uint32_t aStretch,
-                               uint8_t aStyle,
+                               FontStretch aStretch,
+                               FontSlantStyle aStyle,
                                const nsTArray<gfxFontFeature>& aFeatureSettings,
                                const nsTArray<gfxFontVariation>& aVariationSettings,
                                uint32_t aLanguageOverride,
                                gfxCharacterMap* aUnicodeRanges,
                                uint8_t aFontDisplay)
 {
     RefPtr<gfxUserFontEntry> entry;
 
@@ -972,18 +972,18 @@ gfxUserFontSet::FindOrCreateUserFontEntr
 
     return entry.forget();
 }
 
 already_AddRefed<gfxUserFontEntry>
 gfxUserFontSet::CreateUserFontEntry(
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                                FontWeight aWeight,
-                               uint32_t aStretch,
-                               uint8_t aStyle,
+                               FontStretch aStretch,
+                               FontSlantStyle aStyle,
                                const nsTArray<gfxFontFeature>& aFeatureSettings,
                                const nsTArray<gfxFontVariation>& aVariationSettings,
                                uint32_t aLanguageOverride,
                                gfxCharacterMap* aUnicodeRanges,
                                uint8_t aFontDisplay)
 {
 
     RefPtr<gfxUserFontEntry> userFontEntry =
@@ -993,18 +993,18 @@ gfxUserFontSet::CreateUserFontEntry(
     return userFontEntry.forget();
 }
 
 gfxUserFontEntry*
 gfxUserFontSet::FindExistingUserFontEntry(
                                gfxUserFontFamily* aFamily,
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                                FontWeight aWeight,
-                               uint32_t aStretch,
-                               uint8_t aStyle,
+                               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");
@@ -1036,21 +1036,22 @@ void
 gfxUserFontSet::AddUserFontEntry(const nsAString& aFamilyName,
                                  gfxUserFontEntry* aUserFontEntry)
 {
     gfxUserFontFamily* family = GetFamily(aFamilyName);
     family->AddFontEntry(aUserFontEntry);
 
     if (LOG_ENABLED()) {
         LOG(("userfonts (%p) added to \"%s\" (%p) style: %s weight: %g "
-             "stretch: %d display: %d",
+             "stretch: %g%% display: %d",
              this, NS_ConvertUTF16toUTF8(aFamilyName).get(), aUserFontEntry,
              (aUserFontEntry->IsItalic() ? "italic" :
               (aUserFontEntry->IsOblique() ? "oblique" : "normal")),
-             aUserFontEntry->Weight().ToFloat(), aUserFontEntry->Stretch(),
+             aUserFontEntry->Weight().ToFloat(),
+             aUserFontEntry->Stretch().Percentage(),
              aUserFontEntry->GetFontDisplay()));
     }
 }
 
 void
 gfxUserFontSet::IncrementGeneration(bool aIsRebuild)
 {
     // add one, increment again if zero
--- a/gfx/thebes/gfxUserFontSet.h
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -180,16 +180,18 @@ public:
 class gfxUserFontEntry;
 class gfxOTSContext;
 
 class gfxUserFontSet {
     friend class gfxUserFontEntry;
     friend class gfxOTSContext;
 
 public:
+    typedef mozilla::FontStretch FontStretch;
+    typedef mozilla::FontSlantStyle FontSlantStyle;
     typedef mozilla::FontWeight FontWeight;
 
     NS_INLINE_DECL_THREADSAFE_REFCOUNTING(gfxUserFontSet)
 
     gfxUserFontSet();
 
     enum {
         // no flags ==> no hint set
@@ -220,39 +222,39 @@ public:
 
         // mask of all unused bits, update when adding new formats
         FLAG_FORMAT_NOT_USED       = ~((1 << 12)-1)
     };
 
 
     // creates a font face without adding it to a particular family
     // weight - [100, 900] (multiples of 100)
-    // stretch = [NS_FONT_STRETCH_ULTRA_CONDENSED, NS_FONT_STRETCH_ULTRA_EXPANDED]
+    // stretch = [FontStretch::UltraCondensed(), FontStretch::UltraExpanded()]
     // italic style = constants in gfxFontConstants.h, e.g. NS_FONT_STYLE_NORMAL
     // language override = result of calling nsRuleNode::ParseFontLanguageOverride
     // TODO: support for unicode ranges not yet implemented
     virtual already_AddRefed<gfxUserFontEntry> CreateUserFontEntry(
                               const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                               FontWeight aWeight,
-                              uint32_t aStretch,
-                              uint8_t aStyle,
+                              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,
                                FontWeight aWeight,
-                               uint32_t aStretch,
-                               uint8_t aStyle,
+                               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,
@@ -402,19 +404,20 @@ public:
                 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->mWeight.ForHash(),
-                                            (aKey->mFontEntry->mStyle |
-                                             (aKey->mFontEntry->mStretch << 11) ) ^
-                                             aKey->mFontEntry->mLanguageOverride);
+                                            // 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; }
             bool IsPrivate() const { return mPrivate; }
@@ -495,18 +498,18 @@ protected:
     // helper method for performing the actual userfont set rebuild
     virtual void DoRebuildUserFontSet() = 0;
 
     // helper method for FindOrCreateUserFontEntry
     gfxUserFontEntry* FindExistingUserFontEntry(
                                    gfxUserFontFamily* aFamily,
                                    const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                                    FontWeight aWeight,
-                                   uint32_t aStretch,
-                                   uint8_t aStyle,
+                                   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
@@ -534,44 +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,
                      FontWeight aWeight,
-                     uint32_t aStretch,
-                     uint8_t aStyle,
+                     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,
                  FontWeight aWeight,
-                 uint32_t aStretch,
-                 uint8_t aStyle,
+                 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/generic/MathMLTextRunFactory.cpp
+++ b/layout/generic/MathMLTextRunFactory.cpp
@@ -633,22 +633,22 @@ MathMLTextRunFactory::RebuildTextRun(nsT
     if (singleCharMI && mathVar == NS_MATHML_MATHVARIANT_NONE) {
       // If the user has explicitly set a non-default value for fontstyle or
       // fontweight, the italic mathvariant behaviour of <mi> is disabled
       // This overrides the initial values specified in fontStyle, to avoid
       // inconsistencies in which attributes allow CSS changes and which do not.
       if (mFlags & MATH_FONT_WEIGHT_BOLD) {
         font.weight = FontWeight::Bold();
         if (mFlags & MATH_FONT_STYLING_NORMAL) {
-          font.style = NS_FONT_STYLE_NORMAL;
+          font.style = FontSlantStyle::Normal();
         } else {
-          font.style = NS_FONT_STYLE_ITALIC;
+          font.style = FontSlantStyle::Italic();
         }
       } else if (mFlags & MATH_FONT_STYLING_NORMAL) {
-        font.style = NS_FONT_STYLE_NORMAL;
+        font.style = FontSlantStyle::Normal();
         font.weight = FontWeight::Normal();
       } else {
         mathVar = NS_MATHML_MATHVARIANT_ITALIC;
       }
     }
 
     uint32_t ch = str[i];
     if (NS_IS_HIGH_SURROGATE(ch) && i < length - 1 &&
@@ -717,30 +717,30 @@ MathMLTextRunFactory::RebuildTextRun(nsT
   gfxTextRunFactory::Parameters innerParams =
       GetParametersForInner(aTextRun, &flags, aRefDrawTarget);
 
   RefPtr<nsTransformedTextRun> transformedChild;
   RefPtr<gfxTextRun> cachedChild;
   gfxTextRun* child;
 
   if (mathVar == NS_MATHML_MATHVARIANT_BOLD && doMathvariantStyling) {
-    font.style = NS_FONT_STYLE_NORMAL;
+    font.style = FontSlantStyle::Normal();
     font.weight = FontWeight::Bold();
   } else if (mathVar == NS_MATHML_MATHVARIANT_ITALIC && doMathvariantStyling) {
-    font.style = NS_FONT_STYLE_ITALIC;
+    font.style = FontSlantStyle::Italic();
     font.weight = FontWeight::Normal();
   } else if (mathVar == NS_MATHML_MATHVARIANT_BOLD_ITALIC &&
              doMathvariantStyling) {
-    font.style = NS_FONT_STYLE_ITALIC;
+    font.style = FontSlantStyle::Italic();
     font.weight = FontWeight::Bold();
   } else if (mathVar != NS_MATHML_MATHVARIANT_NONE) {
     // Mathvariant overrides fontstyle and fontweight
     // Need to check to see if mathvariant is actually applied as this function
     // is used for other purposes.
-    font.style = NS_FONT_STYLE_NORMAL;
+    font.style = FontSlantStyle::Normal();
     font.weight = FontWeight::Normal();
   }
   gfxFontGroup* newFontGroup = nullptr;
 
   // Get the correct gfxFontGroup that corresponds to the earlier font changes.
   if (length) {
     font.size = NSToCoordRound(font.size * mFontInflation);
     nsPresContext* pc = styles[0]->mPresContext;
--- a/layout/mathml/nsMathMLTokenFrame.cpp
+++ b/layout/mathml/nsMathMLTokenFrame.cpp
@@ -38,17 +38,17 @@ nsMathMLTokenFrame::GetMathMLFrameType()
 {
   // treat everything other than <mi> as ordinary...
   if (!mContent->IsMathMLElement(nsGkAtoms::mi_)) {
     return eMathMLFrameType_Ordinary;
   }
 
   uint8_t mathVariant = StyleFont()->mMathVariant;
   if ((mathVariant == NS_MATHML_MATHVARIANT_NONE &&
-       (StyleFont()->mFont.style == NS_STYLE_FONT_STYLE_ITALIC ||
+       (StyleFont()->mFont.style == FontSlantStyle::Italic() ||
         HasAnyStateBits(NS_FRAME_IS_IN_SINGLE_CHAR_MI))) ||
       mathVariant == NS_MATHML_MATHVARIANT_ITALIC ||
       mathVariant == NS_MATHML_MATHVARIANT_BOLD_ITALIC ||
       mathVariant == NS_MATHML_MATHVARIANT_SANS_SERIF_ITALIC ||
       mathVariant == NS_MATHML_MATHVARIANT_SANS_SERIF_BOLD_ITALIC) {
     return eMathMLFrameType_ItalicIdentifier;
   }
   return eMathMLFrameType_UprightIdentifier;
--- a/layout/style/FontFace.h
+++ b/layout/style/FontFace.h
@@ -44,18 +44,18 @@ class FontFace final : public nsISupport
 public:
   class Entry final : public gfxUserFontEntry {
     friend class FontFace;
 
   public:
     Entry(gfxUserFontSet* aFontSet,
           const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
           FontWeight aWeight,
-          uint32_t aStretch,
-          uint8_t aStyle,
+          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
@@ -203,37 +203,57 @@ FontFaceSet::RemoveDOMContentLoadedListe
   }
 }
 
 void
 FontFaceSet::ParseFontShorthandForMatching(
                             const nsAString& aFont,
                             RefPtr<SharedFontList>& aFamilyList,
                             FontWeight& aWeight,
-                            uint32_t& aStretch,
-                            uint8_t& aStyle,
+                            FontStretch& aStretch,
+                            FontSlantStyle& aStyle,
                             ErrorResult& aRv)
 {
   nsCSSValue style;
   nsCSSValue stretch;
   nsCSSValue weight;
+
+  // FIXME(emilio): This Servo -> nsCSSValue -> Gecko conversion is stupid,
+  // Servo understands the font types.
   RefPtr<URLExtraData> url = ServoCSSParser::GetURLExtraData(mDocument);
   if (!ServoCSSParser::ParseFontShorthandForMatching(
         aFont, url, aFamilyList, style, stretch, weight)) {
     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
     return;
   }
+
+  switch (style.GetUnit()) {
+    case eCSSUnit_Normal:
+      aStyle = FontSlantStyle::Normal();
+      break;
+    case eCSSUnit_Enumerated:
+      MOZ_ASSERT(style.GetIntValue() == NS_FONT_STYLE_ITALIC);
+      aStyle = FontSlantStyle::Italic();
+      break;
+    case eCSSUnit_FontSlantStyle:
+      aStyle = style.GetFontSlantStyle();
+      break;
+    default:
+      MOZ_ASSERT_UNREACHABLE("Unknown unit for font-style");
+  }
+
   if (weight.GetUnit() == eCSSUnit_FontWeight) {
     aWeight = weight.GetFontWeight();
   } else {
     MOZ_ASSERT(weight.GetUnit() == eCSSUnit_Enumerated);
     aWeight = FontWeight(weight.GetIntValue());
   }
-  aStretch = stretch.GetIntValue();
-  aStyle = style.GetIntValue();
+
+  MOZ_ASSERT(stretch.GetUnit() == eCSSUnit_FontStretch);
+  aStretch = stretch.GetFontStretch();
 }
 
 static bool
 HasAnyCharacterInUnicodeRange(gfxUserFontEntry* aEntry,
                               const nsAString& aInput)
 {
   const char16_t* p = aInput.Data();
   const char16_t* end = p + aInput.Length();
@@ -250,18 +270,18 @@ HasAnyCharacterInUnicodeRange(gfxUserFon
 void
 FontFaceSet::FindMatchingFontFaces(const nsAString& aFont,
                                    const nsAString& aText,
                                    nsTArray<FontFace*>& aFontFaces,
                                    ErrorResult& aRv)
 {
   RefPtr<SharedFontList> familyList;
   FontWeight weight;
-  uint32_t stretch;
-  uint8_t italicStyle;
+  FontStretch stretch;
+  FontSlantStyle italicStyle;
   ParseFontShorthandForMatching(aFont, familyList, weight, stretch, italicStyle,
                                 aRv);
   if (aRv.Failed()) {
     return;
   }
 
   gfxFontStyle style;
   style.style = italicStyle;
@@ -974,58 +994,78 @@ GetWeightForDescriptor(const nsCSSValue&
       // 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 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 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 */ already_AddRefed<gfxUserFontEntry>
 FontFaceSet::FindOrCreateUserFontEntryFromFontFace(const nsAString& aFamilyName,
                                                    FontFace* aFontFace,
                                                    SheetType aSheetType)
 {
   FontFaceSet* set = aFontFace->GetPrimaryFontFaceSet();
 
   nsCSSValue val;
   nsCSSUnit unit;
 
-  uint32_t stretch = NS_STYLE_FONT_STRETCH_NORMAL;
-  uint8_t italicStyle = NS_STYLE_FONT_STYLE_NORMAL;
   uint32_t languageOverride = NO_FONT_LANGUAGE_OVERRIDE;
   uint8_t fontDisplay = NS_FONT_DISPLAY_AUTO;
 
   // set up weight
   aFontFace->GetDesc(eCSSFontDesc_Weight, val);
   FontWeight weight = GetWeightForDescriptor(val);
 
   // set up stretch
   aFontFace->GetDesc(eCSSFontDesc_Stretch, val);
-  unit = val.GetUnit();
-  if (unit == eCSSUnit_Enumerated) {
-    stretch = val.GetIntValue();
-  } else if (unit == eCSSUnit_Normal) {
-    stretch = NS_STYLE_FONT_STRETCH_NORMAL;
-  } else {
-    NS_ASSERTION(unit == eCSSUnit_Null,
-                 "@font-face stretch has unexpected unit");
-  }
+  FontStretch stretch = GetStretchForDescriptor(val);
 
   // set up font style
   aFontFace->GetDesc(eCSSFontDesc_Style, val);
-  unit = val.GetUnit();
-  if (unit == eCSSUnit_Enumerated) {
-    italicStyle = val.GetIntValue();
-  } else if (unit == eCSSUnit_Normal) {
-    italicStyle = NS_STYLE_FONT_STYLE_NORMAL;
-  } else {
-    NS_ASSERTION(unit == eCSSUnit_Null,
-                 "@font-face style has unexpected unit");
-  }
+  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,
@@ -1245,23 +1285,22 @@ FontFaceSet::LogMessage(gfxUserFontEntry
   }
 
   nsAutoCString familyName;
   nsAutoCString fontURI;
   aUserFontEntry->GetFamilyNameAndURIForLogging(familyName, fontURI);
 
   nsPrintfCString message
        ("downloadable font: %s "
-        "(font-family: \"%s\" style:%s weight:%g stretch:%s src index:%d)",
+        "(font-family: \"%s\" style:%s weight:%g stretch:%g%% src index:%d)",
         aMessage,
         familyName.get(),
         aUserFontEntry->IsItalic() ? "italic" : "normal",
         aUserFontEntry->Weight().ToFloat(),
-        nsCSSProps::ValueToKeyword(aUserFontEntry->Stretch(),
-                                   nsCSSProps::kFontStretchKTable).get(),
+        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;
@@ -1923,18 +1962,18 @@ FontFaceSet::UserFontSet::DoRebuildUserF
   }
   mFontFaceSet->MarkUserFontSetDirty();
 }
 
 /* virtual */ already_AddRefed<gfxUserFontEntry>
 FontFaceSet::UserFontSet::CreateUserFontEntry(
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                                FontWeight aWeight,
-                               uint32_t aStretch,
-                               uint8_t aStyle,
+                               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
@@ -94,18 +94,18 @@ public:
     virtual nsresult LogMessage(gfxUserFontEntry* aUserFontEntry,
                                 const char* aMessage,
                                 uint32_t aFlags = nsIScriptError::errorFlag,
                                 nsresult aStatus = NS_OK) override;
     virtual void DoRebuildUserFontSet() override;
     already_AddRefed<gfxUserFontEntry> CreateUserFontEntry(
                                    const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                                    FontWeight aWeight,
-                                   uint32_t aStretch,
-                                   uint8_t aStyle,
+                                   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;
@@ -309,18 +309,18 @@ private:
 
   // Helper function for HasLoadingFontFaces.
   void UpdateHasLoadingFontFaces();
 
   void ParseFontShorthandForMatching(
               const nsAString& aFont,
               RefPtr<SharedFontList>& aFamilyList,
               FontWeight& aWeight,
-              uint32_t& aStretch,
-              uint8_t& aStyle,
+              FontStretch& aStretch,
+              FontSlantStyle& aStyle,
               ErrorResult& aRv);
   void FindMatchingFontFaces(const nsAString& aFont,
                              const nsAString& aText,
                              nsTArray<FontFace*>& aFontFaces,
                              mozilla::ErrorResult& aRv);
 
   void DispatchLoadingEventAndReplaceReadyPromise();
   void DispatchCheckLoadingFinishedAfterDelay();
--- a/layout/style/GenericSpecifiedValues.h
+++ b/layout/style/GenericSpecifiedValues.h
@@ -9,16 +9,17 @@
  * could potentially be Servo- or Gecko- format. Used to make attribute mapping
  * code generic over style backends.
  */
 
 #ifndef mozilla_GenericSpecifiedValues_h
 #define mozilla_GenericSpecifiedValues_h
 
 #include "mozilla/ServoUtils.h"
+#include "mozilla/FontPropertyTypes.h"
 #include "nsCSSProps.h"
 #include "nsCSSValue.h"
 #include "nsColor.h"
 
 class nsAttrValue;
 
 namespace mozilla {
 
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -1325,16 +1325,65 @@ Gecko_AppendFeatureValueHashEntry(gfxFon
 void
 Gecko_nsFont_SetFontFeatureValuesLookup(nsFont* aFont,
                                         const RawGeckoPresContext* aPresContext)
 {
   aFont->featureValueLookup = aPresContext->GetFontFeatureValuesLookup();
 }
 
 float
+Gecko_FontStretch_ToFloat(mozilla::FontStretch aStretch)
+{
+  // Servo represents percentages with 1. being 100%.
+  return aStretch.Percentage() / 100.0f;
+}
+
+void
+Gecko_FontStretch_SetFloat(mozilla::FontStretch* aStretch, float aFloat)
+{
+  // Servo represents percentages with 1. being 100%.
+  //
+  // Also, the font code assumes a given maximum that style doesn't really need
+  // to know about. So clamp here at the boundary.
+  *aStretch = FontStretch(std::min(aFloat * 100.0f, float(FontStretch::kMax)));
+}
+
+void
+Gecko_FontSlantStyle_SetNormal(mozilla::FontSlantStyle* aStyle)
+{
+  *aStyle = mozilla::FontSlantStyle::Normal();
+}
+
+void
+Gecko_FontSlantStyle_SetItalic(mozilla::FontSlantStyle* aStyle)
+{
+  *aStyle = mozilla::FontSlantStyle::Italic();
+}
+
+void
+Gecko_FontSlantStyle_SetOblique(mozilla::FontSlantStyle* aStyle,
+                                float aAngleInDegrees)
+{
+  *aStyle = mozilla::FontSlantStyle::Oblique(aAngleInDegrees);
+}
+
+void
+Gecko_FontSlantStyle_Get(mozilla::FontSlantStyle aStyle,
+                         bool* aNormal,
+                         bool* aItalic,
+                         float* aObliqueAngle)
+{
+  *aNormal = aStyle.IsNormal();
+  *aItalic = aStyle.IsItalic();
+  if (aStyle.IsOblique()) {
+    *aObliqueAngle = aStyle.ObliqueAngle();
+  }
+}
+
+float
 Gecko_FontWeight_ToFloat(mozilla::FontWeight aWeight)
 {
   return aWeight.ToFloat();
 }
 
 void
 Gecko_FontWeight_SetFloat(mozilla::FontWeight* aWeight,
                           float aFloat)
@@ -2317,16 +2366,32 @@ Gecko_CSSValue_InitSharedList(nsCSSValue
 
 void
 Gecko_CSSValue_Drop(nsCSSValueBorrowedMut aCSSValue)
 {
   aCSSValue->~nsCSSValue();
 }
 
 void
+Gecko_CSSValue_SetFontStretch(nsCSSValueBorrowedMut aCSSValue,
+                              float stretch)
+{
+  aCSSValue->SetFontStretch(
+    FontStretch(std::min(stretch * 100.0f, float(FontStretch::kMax))));
+}
+
+// FIXME(emilio): This function should probably have `Oblique` in its name.
+void
+Gecko_CSSValue_SetFontSlantStyle(nsCSSValueBorrowedMut aCSSValue,
+                                 float aAngle)
+{
+  aCSSValue->SetFontSlantStyle(mozilla::FontSlantStyle::Oblique(aAngle));
+}
+
+void
 Gecko_CSSValue_SetFontWeight(nsCSSValueBorrowedMut aCSSValue,
                              float weight)
 {
   aCSSValue->SetFontWeight(mozilla::FontWeight(weight));
 }
 
 void
 Gecko_nsStyleFont_SetLang(nsStyleFont* aFont, nsAtom* aAtom)
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -569,16 +569,18 @@ float Gecko_CSSValue_GetNumber(nsCSSValu
 float Gecko_CSSValue_GetPercentage(nsCSSValueBorrowed css_value);
 nsStyleCoord::CalcValue Gecko_CSSValue_GetCalc(nsCSSValueBorrowed aCSSValue);
 
 void Gecko_CSSValue_SetNumber(nsCSSValueBorrowedMut css_value, float number);
 void Gecko_CSSValue_SetKeyword(nsCSSValueBorrowedMut css_value, nsCSSKeyword keyword);
 void Gecko_CSSValue_SetPercentage(nsCSSValueBorrowedMut css_value, float percent);
 void Gecko_CSSValue_SetPixelLength(nsCSSValueBorrowedMut aCSSValue, float aLen);
 void Gecko_CSSValue_SetCalc(nsCSSValueBorrowedMut css_value, nsStyleCoord::CalcValue calc);
+void Gecko_CSSValue_SetFontStretch(nsCSSValueBorrowedMut css_value, float stretch);
+void Gecko_CSSValue_SetFontSlantStyle(nsCSSValueBorrowedMut css_value, float style);
 void Gecko_CSSValue_SetFontWeight(nsCSSValueBorrowedMut css_value, float weight);
 void Gecko_CSSValue_SetFunction(nsCSSValueBorrowedMut css_value, int32_t len);
 void Gecko_CSSValue_SetString(nsCSSValueBorrowedMut css_value,
                               const uint8_t* string, uint32_t len, nsCSSUnit unit);
 void Gecko_CSSValue_SetStringFromAtom(nsCSSValueBorrowedMut css_value,
                                       nsAtom* atom, nsCSSUnit unit);
 // Take an addrefed nsAtom and set it to the nsCSSValue
 void Gecko_CSSValue_SetAtomIdent(nsCSSValueBorrowedMut css_value, nsAtom* atom);
@@ -589,16 +591,28 @@ void Gecko_CSSValue_SetFloat(nsCSSValueB
 void Gecko_CSSValue_SetPair(nsCSSValueBorrowedMut css_value,
                             nsCSSValueBorrowed xvalue, nsCSSValueBorrowed yvalue);
 void Gecko_CSSValue_SetList(nsCSSValueBorrowedMut css_value, uint32_t len);
 void Gecko_CSSValue_SetPairList(nsCSSValueBorrowedMut css_value, uint32_t len);
 void Gecko_CSSValue_InitSharedList(nsCSSValueBorrowedMut css_value, uint32_t len);
 void Gecko_CSSValue_Drop(nsCSSValueBorrowedMut css_value);
 NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsCSSValueSharedList, CSSValueSharedList);
 
+float Gecko_FontStretch_ToFloat(mozilla::FontStretch aStretch);
+void Gecko_FontStretch_SetFloat(mozilla::FontStretch* aStretch,
+                                float aFloatValue);
+float Gecko_FontSlantStyle_ToFloat(mozilla::FontSlantStyle aStyle);
+void Gecko_FontSlantStyle_SetNormal(mozilla::FontSlantStyle*);
+void Gecko_FontSlantStyle_SetItalic(mozilla::FontSlantStyle*);
+void Gecko_FontSlantStyle_SetOblique(mozilla::FontSlantStyle*, float angle_degrees);
+void Gecko_FontSlantStyle_Get(mozilla::FontSlantStyle,
+                              bool* normal,
+                              bool* italic,
+                              float* oblique_angle);
+
 float Gecko_FontWeight_ToFloat(mozilla::FontWeight aWeight);
 void Gecko_FontWeight_SetFloat(mozilla::FontWeight* aWeight,
                                float aFloatValue);
 
 void Gecko_nsStyleFont_SetLang(nsStyleFont* font, nsAtom* atom);
 void Gecko_nsStyleFont_CopyLangFrom(nsStyleFont* aFont, const nsStyleFont* aSource);
 void Gecko_nsStyleFont_FixupNoneGeneric(nsStyleFont* font,
                                         RawGeckoPresContextBorrowed pres_context);
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -454,16 +454,18 @@ structs-types = [
     "mozilla::css::GridTemplateAreasValue",
     "mozilla::css::ErrorReporter",
     "mozilla::css::ImageValue",
     "mozilla::css::URLValue",
     "mozilla::css::URLValueData",
     "mozilla::dom::CallerType",
     "mozilla::AnonymousCounterStyle",
     "mozilla::AtomArray",
+    "mozilla::FontStretch",
+    "mozilla::FontSlantStyle",
     "mozilla::FontWeight",
     "mozilla::MallocSizeOf",
     "mozilla::OriginFlags",
     "mozilla::UniquePtr",
     "ServoRawOffsetArc",
     "nsIContent",
     "nsIDocument",
     "nsIDocument_DocumentTheme",
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -1353,32 +1353,38 @@ const KTableEntry nsCSSProps::kFontSizeK
 
 const KTableEntry nsCSSProps::kFontSmoothingKTable[] = {
   { eCSSKeyword_auto, NS_FONT_SMOOTHING_AUTO },
   { eCSSKeyword_grayscale, NS_FONT_SMOOTHING_GRAYSCALE },
   { eCSSKeyword_UNKNOWN, -1 }
 };
 
 const KTableEntry nsCSSProps::kFontStretchKTable[] = {
-  { eCSSKeyword_ultra_condensed, NS_STYLE_FONT_STRETCH_ULTRA_CONDENSED },
-  { eCSSKeyword_extra_condensed, NS_STYLE_FONT_STRETCH_EXTRA_CONDENSED },
-  { eCSSKeyword_condensed, NS_STYLE_FONT_STRETCH_CONDENSED },
-  { eCSSKeyword_semi_condensed, NS_STYLE_FONT_STRETCH_SEMI_CONDENSED },
-  { eCSSKeyword_normal, NS_STYLE_FONT_STRETCH_NORMAL },
-  { eCSSKeyword_semi_expanded, NS_STYLE_FONT_STRETCH_SEMI_EXPANDED },
-  { eCSSKeyword_expanded, NS_STYLE_FONT_STRETCH_EXPANDED },
-  { eCSSKeyword_extra_expanded, NS_STYLE_FONT_STRETCH_EXTRA_EXPANDED },
-  { eCSSKeyword_ultra_expanded, NS_STYLE_FONT_STRETCH_ULTRA_EXPANDED },
+  // The spec defines some keywords to be fractional values, which we can't
+  // represent in this table.  We use dummy values since no code cares about
+  // the actual values that we use here anyway, and this code is going away
+  // in bug 1448759.
+  { eCSSKeyword_ultra_condensed, 1001 },
+  { eCSSKeyword_extra_condensed, 1001 },
+  { eCSSKeyword_condensed, 1001 },
+  { eCSSKeyword_semi_condensed, 1001 },
+  { eCSSKeyword_normal, 1001 },
+  { eCSSKeyword_semi_expanded, 1001 },
+  { eCSSKeyword_expanded, 1001 },
+  { eCSSKeyword_extra_expanded, 1001 },
+  { eCSSKeyword_ultra_expanded, 1001 },
   { eCSSKeyword_UNKNOWN, -1 }
 };
 
 const KTableEntry nsCSSProps::kFontStyleKTable[] = {
-  { eCSSKeyword_normal, NS_STYLE_FONT_STYLE_NORMAL },
-  { eCSSKeyword_italic, NS_STYLE_FONT_STYLE_ITALIC },
-  { eCSSKeyword_oblique, NS_STYLE_FONT_STYLE_OBLIQUE },
+  // Dummy values.  No code cares any more about the actual values, and this
+  // code is going away in bug 1448759.
+  { eCSSKeyword_normal, 361 },
+  { eCSSKeyword_italic, 361 },
+  { eCSSKeyword_oblique, 361 },
   { eCSSKeyword_UNKNOWN, -1 }
 };
 
 const KTableEntry nsCSSProps::kFontSynthesisKTable[] = {
   { eCSSKeyword_weight, NS_FONT_SYNTHESIS_WEIGHT },
   { eCSSKeyword_style, NS_FONT_SYNTHESIS_STYLE },
   { eCSSKeyword_UNKNOWN, -1 }
 };
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -117,16 +117,28 @@ nsCSSValue::nsCSSValue(mozilla::css::Gri
 
 nsCSSValue::nsCSSValue(SharedFontList* aValue)
   : mUnit(eCSSUnit_FontFamilyList)
 {
   mValue.mFontFamilyList = aValue;
   mValue.mFontFamilyList->AddRef();
 }
 
+nsCSSValue::nsCSSValue(FontStretch aStretch)
+  : mUnit(eCSSUnit_FontStretch)
+{
+  mValue.mFontStretch = aStretch;
+}
+
+nsCSSValue::nsCSSValue(FontSlantStyle aStyle)
+  : mUnit(eCSSUnit_FontSlantStyle)
+{
+  mValue.mFontSlantStyle = aStyle;
+}
+
 nsCSSValue::nsCSSValue(FontWeight aWeight)
   : mUnit(eCSSUnit_FontWeight)
 {
   mValue.mFontWeight = aWeight;
 }
 
 nsCSSValue::nsCSSValue(const nsCSSValue& aCopy)
   : mUnit(aCopy.mUnit)
@@ -182,16 +194,22 @@ nsCSSValue::nsCSSValue(const nsCSSValue&
   else if (eCSSUnit_GridTemplateAreas == mUnit) {
     mValue.mGridTemplateAreas = aCopy.mValue.mGridTemplateAreas;
     mValue.mGridTemplateAreas->AddRef();
   }
   else if (eCSSUnit_FontFamilyList == mUnit) {
     mValue.mFontFamilyList = aCopy.mValue.mFontFamilyList;
     mValue.mFontFamilyList->AddRef();
   }
+  else if (eCSSUnit_FontStretch == mUnit) {
+    mValue.mFontStretch = aCopy.mValue.mFontStretch;
+  }
+  else if (eCSSUnit_FontSlantStyle == mUnit) {
+    mValue.mFontSlantStyle = aCopy.mValue.mFontSlantStyle;
+  }
   else if (eCSSUnit_FontWeight == mUnit) {
     mValue.mFontWeight = aCopy.mValue.mFontWeight;
   }
   else if (eCSSUnit_AtomIdent == mUnit) {
     mValue.mAtom = aCopy.mValue.mAtom;
     mValue.mAtom->AddRef();
   }
   else {
@@ -264,16 +282,22 @@ bool nsCSSValue::operator==(const nsCSSV
     }
     else if (eCSSUnit_GridTemplateAreas == mUnit) {
       return *mValue.mGridTemplateAreas == *aOther.mValue.mGridTemplateAreas;
     }
     else if (eCSSUnit_FontFamilyList == mUnit) {
       return mValue.mFontFamilyList->mNames ==
              aOther.mValue.mFontFamilyList->mNames;
     }
+    else if (eCSSUnit_FontStretch == mUnit) {
+      return mValue.mFontStretch == aOther.mValue.mFontStretch;
+    }
+    else if (eCSSUnit_FontSlantStyle == mUnit) {
+      return mValue.mFontSlantStyle == aOther.mValue.mFontSlantStyle;
+    }
     else if (eCSSUnit_FontWeight == mUnit) {
       return mValue.mFontWeight == aOther.mValue.mFontWeight;
     }
     else if (eCSSUnit_AtomIdent == mUnit) {
       return mValue.mAtom == aOther.mValue.mAtom;
     }
     else {
       return mValue.mFloat == aOther.mValue.mFloat;
@@ -485,16 +509,30 @@ void nsCSSValue::SetGridTemplateAreas(mo
 
 void nsCSSValue::SetFontFamilyListValue(already_AddRefed<SharedFontList> aValue)
 {
   Reset();
   mUnit = eCSSUnit_FontFamilyList;
   mValue.mFontFamilyList = aValue.take();
 }
 
+void nsCSSValue::SetFontStretch(FontStretch aStretch)
+{
+  Reset();
+  mUnit = eCSSUnit_FontStretch;
+  mValue.mFontStretch = aStretch;
+}
+
+void nsCSSValue::SetFontSlantStyle(FontSlantStyle aStyle)
+{
+  Reset();
+  mUnit = eCSSUnit_FontSlantStyle;
+  mValue.mFontSlantStyle = aStyle;
+}
+
 void nsCSSValue::SetFontWeight(FontWeight aWeight)
 {
   Reset();
   mUnit = eCSSUnit_FontWeight;
   mValue.mFontWeight = aWeight;
 }
 
 void nsCSSValue::SetPairValue(const nsCSSValuePair* aValue)
@@ -914,16 +952,18 @@ nsCSSValue::SizeOfExcludingThis(mozilla:
 
     // Atom is always shared, and thus should not be counted.
     case eCSSUnit_AtomIdent:
       break;
 
     // Int: nothing extra to measure.
     case eCSSUnit_Integer:
     case eCSSUnit_Enumerated:
+    case eCSSUnit_FontStretch:
+    case eCSSUnit_FontSlantStyle:
     case eCSSUnit_FontWeight:
       break;
 
     // Float: nothing extra to measure.
     case eCSSUnit_Percent:
     case eCSSUnit_Number:
     case eCSSUnit_ViewportWidth:
     case eCSSUnit_ViewportHeight:
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -441,16 +441,18 @@ enum nsCSSUnit {
   eCSSUnit_Seconds      = 3000,    // (float) Standard time
   eCSSUnit_Milliseconds = 3001,    // (float) 1/1000 second
 
   // Flexible fraction (CSS Grid)
   eCSSUnit_FlexFraction = 4000,    // (float) Fraction of free space
 
   // Font property types
   eCSSUnit_FontWeight   = 5000,    // An encoded font-weight
+  eCSSUnit_FontStretch  = 5001,    // An encoded font-stretch
+  eCSSUnit_FontSlantStyle    = 5002,    // An encoded font-style
 };
 
 struct nsCSSValuePair;
 struct nsCSSValuePair_heap;
 struct nsCSSValueList;
 struct nsCSSValueList_heap;
 struct nsCSSValueSharedList;
 struct nsCSSValuePairList;
@@ -475,16 +477,18 @@ public:
   nsCSSValue(int32_t aValue, nsCSSUnit aUnit);
   nsCSSValue(float aValue, nsCSSUnit aUnit);
   nsCSSValue(const nsString& aValue, nsCSSUnit aUnit);
   nsCSSValue(Array* aArray, nsCSSUnit aUnit);
   explicit nsCSSValue(mozilla::css::URLValue* aValue);
   explicit nsCSSValue(mozilla::css::ImageValue* aValue);
   explicit nsCSSValue(mozilla::css::GridTemplateAreasValue* aValue);
   explicit nsCSSValue(mozilla::SharedFontList* aValue);
+  explicit nsCSSValue(mozilla::FontStretch aStretch);
+  explicit nsCSSValue(mozilla::FontSlantStyle aStyle);
   explicit nsCSSValue(mozilla::FontWeight aWeight);
   nsCSSValue(const nsCSSValue& aCopy);
   nsCSSValue(nsCSSValue&& aOther)
     : mUnit(aOther.mUnit)
     , mValue(aOther.mValue)
   {
     aOther.mUnit = eCSSUnit_Null;
   }
@@ -631,16 +635,28 @@ public:
   {
     MOZ_ASSERT(mUnit == eCSSUnit_FontFamilyList,
                "not a font family list value");
     NS_ASSERTION(mValue.mFontFamilyList != nullptr,
                  "font family list value should never be null");
     return mozilla::WrapNotNull(mValue.mFontFamilyList);
   }
 
+  mozilla::FontStretch GetFontStretch() const
+  {
+    MOZ_ASSERT(mUnit == eCSSUnit_FontStretch, "not a font stretch value");
+    return mValue.mFontStretch;
+  }
+
+  mozilla::FontSlantStyle GetFontSlantStyle() const
+  {
+    MOZ_ASSERT(mUnit == eCSSUnit_FontSlantStyle, "not a font style value");
+    return mValue.mFontSlantStyle;
+  }
+
   mozilla::FontWeight GetFontWeight() const
   {
     MOZ_ASSERT(mUnit == eCSSUnit_FontWeight, "not a font weight value");
     return mValue.mFontWeight;
   }
 
   // bodies of these are below
   inline nsCSSValuePair& GetPairValue();
@@ -714,16 +730,18 @@ public:
   void SetAtomIdentValue(already_AddRefed<nsAtom> aValue);
   // converts the nscoord to pixels
   void SetIntegerCoordValue(nscoord aCoord);
   void SetArrayValue(nsCSSValue::Array* aArray, nsCSSUnit aUnit);
   void SetURLValue(mozilla::css::URLValue* aURI);
   void SetImageValue(mozilla::css::ImageValue* aImage);
   void SetGridTemplateAreas(mozilla::css::GridTemplateAreasValue* aValue);
   void SetFontFamilyListValue(already_AddRefed<mozilla::SharedFontList> aFontListValue);
+  void SetFontStretch(mozilla::FontStretch aStretch);
+  void SetFontSlantStyle(mozilla::FontSlantStyle aStyle);
   void SetFontWeight(mozilla::FontWeight aWeight);
   void SetPairValue(const nsCSSValuePair* aPair);
   void SetPairValue(const nsCSSValue& xValue, const nsCSSValue& yValue);
   void SetSharedListValue(nsCSSValueSharedList* aList);
   void SetDependentListValue(nsCSSValueList* aList);
   void SetDependentPairListValue(nsCSSValuePairList* aList);
   void SetAutoValue();
   void SetInheritValue();
@@ -791,16 +809,18 @@ protected:
     mozilla::css::GridTemplateAreasValue* MOZ_OWNING_REF mGridTemplateAreas;
     nsCSSValuePair_heap* MOZ_OWNING_REF mPair;
     nsCSSValueList_heap* MOZ_OWNING_REF mList;
     nsCSSValueList* mListDependent;
     nsCSSValueSharedList* MOZ_OWNING_REF mSharedList;
     nsCSSValuePairList_heap* MOZ_OWNING_REF mPairList;
     nsCSSValuePairList* mPairListDependent;
     mozilla::SharedFontList* MOZ_OWNING_REF mFontFamilyList;
+    mozilla::FontStretch mFontStretch;
+    mozilla::FontSlantStyle mFontSlantStyle;
     mozilla::FontWeight mFontWeight;
   } mValue;
 };
 
 struct nsCSSValue::Array final {
 
   // return |Array| with reference count of zero
   static Array* Create(size_t aItemCount) {
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -1956,29 +1956,57 @@ nsComputedDOMStyle::DoGetFontSmoothingBa
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFontStretch()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
-  val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.stretch,
-                                               nsCSSProps::kFontStretchKTable));
-
+  const nsStyleFont* font = StyleFont();
+
+  // Chrome does not return keywords, so neither do we.
+  // See w3c/csswg-drafts#2605 for discussion though.
+  float stretch = font->mFont.stretch.Percentage();
+  MOZ_ASSERT(stretch >= 0.f,
+             "unexpected font-stretch value");
+  val->SetPercent(stretch / 100.f);
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFontStyle()
 {
-  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-  val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleFont()->mFont.style,
-                                               nsCSSProps::kFontStyleKTable));
-  return val.forget();
+  const nsStyleFont* font = StyleFont();
+  const FontSlantStyle& style = font->mFont.style;
+
+  // FIXME(emilio): Once we get rid of GetPropertyCSSValue, this can, at least,
+  // get unified with nsStyleUtil::AppendFontSlantStyle.
+  //
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+  if (style.IsNormal() || style.IsItalic()) {
+    auto keyword = style.IsNormal() ? eCSSKeyword_normal : eCSSKeyword_italic;
+    val->SetIdent(keyword);
+    return val.forget();
+  }
+
+  float angle = style.ObliqueAngle();
+  val->SetIdent(eCSSKeyword_oblique);
+  if (angle == FontSlantStyle::kDefaultAngle) {
+    return val.forget();
+  }
+
+  RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
+  valueList->AppendCSSValue(val.forget());
+
+  RefPtr<nsROCSSPrimitiveValue> angleVal = new nsROCSSPrimitiveValue;
+  angleVal->SetDegree(angle);
+  valueList->AppendCSSValue(angleVal.forget());
+
+  return valueList.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetFontWeight()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   const nsStyleFont* font = StyleFont();
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -585,28 +585,16 @@ enum class StyleDisplay : uint8_t {
 #define NS_STYLE_FONT_SIZE_LARGE                4
 #define NS_STYLE_FONT_SIZE_XLARGE               5
 #define NS_STYLE_FONT_SIZE_XXLARGE              6
 #define NS_STYLE_FONT_SIZE_XXXLARGE             7  // Only used by <font size="7">. Not specifiable in CSS.
 #define NS_STYLE_FONT_SIZE_LARGER               8
 #define NS_STYLE_FONT_SIZE_SMALLER              9
 #define NS_STYLE_FONT_SIZE_NO_KEYWORD          10 // Used by Servo to track the "no keyword" case
 
-// See nsStyleFont
-// We should eventually stop using the NS_STYLE_* variants here.
-#define NS_STYLE_FONT_STRETCH_ULTRA_CONDENSED   NS_FONT_STRETCH_ULTRA_CONDENSED
-#define NS_STYLE_FONT_STRETCH_EXTRA_CONDENSED   NS_FONT_STRETCH_EXTRA_CONDENSED
-#define NS_STYLE_FONT_STRETCH_CONDENSED         NS_FONT_STRETCH_CONDENSED
-#define NS_STYLE_FONT_STRETCH_SEMI_CONDENSED    NS_FONT_STRETCH_SEMI_CONDENSED
-#define NS_STYLE_FONT_STRETCH_NORMAL            NS_FONT_STRETCH_NORMAL
-#define NS_STYLE_FONT_STRETCH_SEMI_EXPANDED     NS_FONT_STRETCH_SEMI_EXPANDED
-#define NS_STYLE_FONT_STRETCH_EXPANDED          NS_FONT_STRETCH_EXPANDED
-#define NS_STYLE_FONT_STRETCH_EXTRA_EXPANDED    NS_FONT_STRETCH_EXTRA_EXPANDED
-#define NS_STYLE_FONT_STRETCH_ULTRA_EXPANDED    NS_FONT_STRETCH_ULTRA_EXPANDED
-
 // See nsStyleFont - system fonts
 #define NS_STYLE_FONT_CAPTION                   1   // css2
 #define NS_STYLE_FONT_ICON                      2
 #define NS_STYLE_FONT_MENU                      3
 #define NS_STYLE_FONT_MESSAGE_BOX               4
 #define NS_STYLE_FONT_SMALL_CAPTION             5
 #define NS_STYLE_FONT_STATUS_BAR                6
 #define NS_STYLE_FONT_WINDOW                    7   // css3
--- a/layout/style/nsStyleUtil.cpp
+++ b/layout/style/nsStyleUtil.cpp
@@ -2,16 +2,17 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsStyleUtil.h"
 #include "nsStyleConsts.h"
 
+#include "mozilla/FontPropertyTypes.h"
 #include "nsIContent.h"
 #include "nsCSSProps.h"
 #include "nsContentUtils.h"
 #include "nsROCSSPrimitiveValue.h"
 #include "nsStyleStruct.h"
 #include "nsIContentPolicy.h"
 #include "nsIContentSecurityPolicy.h"
 #include "nsIURI.h"
@@ -875,8 +876,25 @@ nsStyleUtil::CSPAllowsInlineStyle(Elemen
                             nonce,
                             false, // aParserCreated only applies to scripts
                             styleText, aLineNumber,
                             &allowInlineStyle);
   NS_ENSURE_SUCCESS(rv, false);
 
   return allowInlineStyle;
 }
+
+void
+nsStyleUtil::AppendFontSlantStyle(const FontSlantStyle& aStyle, nsAString& aOut)
+{
+  if (aStyle.IsNormal()) {
+    aOut.AppendLiteral("normal");
+  } else if (aStyle.IsItalic()) {
+    aOut.AppendLiteral("italic");
+  } else {
+    aOut.AppendLiteral("oblique");
+    auto angle = aStyle.ObliqueAngle();
+    if (angle != FontSlantStyle::kDefaultAngle) {
+      aOut.AppendLiteral(" ");
+      AppendAngleValue(nsStyleCoord(angle, eStyleUnit_Degree), aOut);
+    }
+  }
+}
--- a/layout/style/nsStyleUtil.h
+++ b/layout/style/nsStyleUtil.h
@@ -18,16 +18,20 @@ class nsCSSValue;
 class nsStyleCoord;
 class nsIContent;
 class nsIPrincipal;
 class nsIURI;
 struct gfxFontFeature;
 struct gfxAlternateValue;
 struct nsCSSValueList;
 
+namespace mozilla {
+class FontSlantStyle;
+}
+
 // Style utility functions
 class nsStyleUtil {
 public:
 
  static bool DashMatchCompare(const nsAString& aAttributeValue,
                                 const nsAString& aSelectorValue,
                                 const nsStringComparator& aComparator);
 
@@ -53,16 +57,19 @@ public:
                                  nsAString& aResult);
   static void
   AppendEscapedCSSFontFamilyList(mozilla::SharedFontList* aFontlist,
                                  nsAString& aResult)
   {
     AppendEscapedCSSFontFamilyList(aFontlist->mNames, aResult);
   }
 
+  static void
+  AppendFontSlantStyle(const mozilla::FontSlantStyle&, nsAString& aResult);
+
 private:
   static void
   AppendEscapedCSSFontFamilyList(const nsTArray<mozilla::FontFamilyName>& aNames,
                                  nsAString& aResult);
 
 public:
   // Append a bitmask-valued property's value(s) (space-separated) to aResult.
   static void AppendBitmaskCSSValue(nsCSSPropertyID aProperty,
--- a/servo/components/style/gecko/rules.rs
+++ b/servo/components/style/gecko/rules.rs
@@ -21,29 +21,22 @@ use values::specified::font::SpecifiedFo
 impl<'a> ToNsCssValue for &'a FamilyName {
     fn convert(self, nscssvalue: &mut nsCSSValue) {
         nscssvalue.set_string_from_atom(&self.name)
     }
 }
 
 impl<'a> ToNsCssValue for &'a SpecifiedFontStretch {
     fn convert(self, nscssvalue: &mut nsCSSValue) {
-        use values::specified::font::FontStretchKeyword;
-        match *self {
-            SpecifiedFontStretch::Stretch(ref p) => nscssvalue.set_number(p.get()),
-            SpecifiedFontStretch::Keyword(ref kw) => {
-                // TODO(emilio): Use this branch instead.
-                if false {
-                    nscssvalue.set_number(kw.compute().0)
-                } else {
-                    nscssvalue.set_enum(FontStretchKeyword::gecko_keyword(kw.compute().0) as i32)
-                }
-            }
+        let number = match *self {
+            SpecifiedFontStretch::Stretch(ref p) => p.get(),
+            SpecifiedFontStretch::Keyword(ref kw) => kw.compute().0,
             SpecifiedFontStretch::System(..) => unreachable!(),
-        }
+        };
+        nscssvalue.set_font_stretch(number);
     }
 }
 
 impl<'a> ToNsCssValue for &'a AbsoluteFontWeight {
     fn convert(self, nscssvalue: &mut nsCSSValue) {
         nscssvalue.set_font_weight(self.compute().0)
     }
 }
@@ -118,18 +111,18 @@ impl<'a> ToNsCssValue for &'a FontStyle 
     fn convert(self, nscssvalue: &mut nsCSSValue) {
         match *self {
             FontStyle::Normal => nscssvalue.set_normal(),
             FontStyle::Italic => nscssvalue.set_enum(structs::NS_FONT_STYLE_ITALIC as i32),
             FontStyle::Oblique(ref first, ref second) => {
                 let mut a = nsCSSValue::null();
                 let mut b = nsCSSValue::null();
 
-                a.set_angle(SpecifiedFontStyle::compute_angle(first));
-                b.set_angle(SpecifiedFontStyle::compute_angle(second));
+                a.set_font_style(SpecifiedFontStyle::compute_angle(first).degrees());
+                b.set_font_style(SpecifiedFontStyle::compute_angle(second).degrees());
 
                 nscssvalue.set_pair(&a, &b);
             }
         }
     }
 }
 
 impl<'a> ToNsCssValue for &'a font_language_override::SpecifiedValue {
--- a/servo/components/style/gecko_bindings/sugar/ns_css_value.rs
+++ b/servo/components/style/gecko_bindings/sugar/ns_css_value.rs
@@ -162,26 +162,36 @@ impl nsCSSValue {
         self.set_string_internal(s, nsCSSUnit::eCSSUnit_Ident)
     }
 
     /// Set to an atom identifier value
     pub fn set_atom_ident(&mut self, s: Atom) {
         unsafe { bindings::Gecko_CSSValue_SetAtomIdent(self, s.into_addrefed()) }
     }
 
-    /// Set to a font format
+    /// Set to a font format.
     pub fn set_font_format(&mut self, s: &str) {
         self.set_string_internal(s, nsCSSUnit::eCSSUnit_Font_Format);
     }
 
-    /// Set to a local font value
+    /// Set to a local font value.
     pub fn set_local_font(&mut self, s: &Atom) {
         self.set_string_from_atom_internal(s, nsCSSUnit::eCSSUnit_Local_Font);
     }
 
+    /// Set to a font stretch.
+    pub fn set_font_stretch(&mut self, s: f32) {
+        unsafe { bindings::Gecko_CSSValue_SetFontStretch(self, s) }
+    }
+
+    /// Set to a font style
+    pub fn set_font_style(&mut self, s: f32) {
+        unsafe { bindings::Gecko_CSSValue_SetFontSlantStyle(self, s) }
+    }
+
     /// Set to a font weight
     pub fn set_font_weight(&mut self, w: f32) {
         unsafe { bindings::Gecko_CSSValue_SetFontWeight(self, w) }
     }
 
     fn set_int_internal(&mut self, value: i32, unit: nsCSSUnit) {
         unsafe { bindings::Gecko_CSSValue_SetInt(self, value, unit) }
     }
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -20,18 +20,16 @@ use gecko_bindings::bindings::Gecko_Copy
 use gecko_bindings::bindings::Gecko_Destroy_${style_struct.gecko_ffi_name};
 % endfor
 use gecko_bindings::bindings::Gecko_CopyCounterStyle;
 use gecko_bindings::bindings::Gecko_CopyCursorArrayFrom;
 use gecko_bindings::bindings::Gecko_CopyFontFamilyFrom;
 use gecko_bindings::bindings::Gecko_CopyImageValueFrom;
 use gecko_bindings::bindings::Gecko_CopyListStyleImageFrom;
 use gecko_bindings::bindings::Gecko_EnsureImageLayersLength;
-use gecko_bindings::bindings::Gecko_FontWeight_SetFloat;
-use gecko_bindings::bindings::Gecko_FontWeight_ToFloat;
 use gecko_bindings::bindings::Gecko_SetCursorArrayLength;
 use gecko_bindings::bindings::Gecko_SetCursorImageValue;
 use gecko_bindings::bindings::Gecko_StyleTransition_SetUnsupportedProperty;
 use gecko_bindings::bindings::Gecko_NewCSSShadowArray;
 use gecko_bindings::bindings::Gecko_nsStyleFont_SetLang;
 use gecko_bindings::bindings::Gecko_nsStyleFont_CopyLangFrom;
 use gecko_bindings::bindings::Gecko_SetListStyleImageNone;
 use gecko_bindings::bindings::Gecko_SetListStyleImageImageValue;
@@ -2596,47 +2594,54 @@ fn static_assert() {
                 kw: kw,
                 factor: self.gecko.mFontSizeFactor,
                 offset: Au(self.gecko.mFontSizeOffset).into()
             })
         }
     }
 
     pub fn set_font_weight(&mut self, v: longhands::font_weight::computed_value::T) {
-        unsafe { Gecko_FontWeight_SetFloat(&mut self.gecko.mFont.weight, v.0) };
+        unsafe { bindings::Gecko_FontWeight_SetFloat(&mut self.gecko.mFont.weight, v.0) };
     }
     ${impl_simple_copy('font_weight', 'mFont.weight')}
 
     pub fn clone_font_weight(&self) -> longhands::font_weight::computed_value::T {
-        let weight: f32 = unsafe { Gecko_FontWeight_ToFloat(self.gecko.mFont.weight) };
+        let weight: f32 = unsafe {
+            bindings::Gecko_FontWeight_ToFloat(self.gecko.mFont.weight)
+        };
         longhands::font_weight::computed_value::T(weight)
     }
 
     pub fn set_font_stretch(&mut self, v: longhands::font_stretch::computed_value::T) {
         unsafe { bindings::Gecko_FontStretch_SetFloat(&mut self.gecko.mFont.stretch, (v.0).0) };
     }
     ${impl_simple_copy('font_stretch', 'mFont.stretch')}
     pub fn clone_font_stretch(&self) -> longhands::font_stretch::computed_value::T {
         use values::computed::Percentage;
         use values::generics::NonNegative;
 
-        let stretch = self.gecko.mFont.stretch as f32 / 100.;
+        let stretch =
+            unsafe { bindings::Gecko_FontStretch_ToFloat(self.gecko.mFont.stretch) };
         debug_assert!(stretch >= 0.);
 
         NonNegative(Percentage(stretch))
     }
 
     pub fn set_font_style(&mut self, v: longhands::font_style::computed_value::T) {
         use values::generics::font::FontStyle;
-        self.gecko.mFont.style = match v {
-            FontStyle::Normal => structs::NS_STYLE_FONT_STYLE_NORMAL,
-            FontStyle::Italic => structs::NS_STYLE_FONT_STYLE_ITALIC,
-            // FIXME(emilio): Honor the angle.
-            FontStyle::Oblique(ref _angle) => structs::NS_STYLE_FONT_STYLE_OBLIQUE,
-        } as u8;
+        let s = &mut self.gecko.mFont.style;
+        unsafe {
+            match v {
+                FontStyle::Normal => bindings::Gecko_FontSlantStyle_SetNormal(s),
+                FontStyle::Italic => bindings::Gecko_FontSlantStyle_SetItalic(s),
+                FontStyle::Oblique(ref angle) => {
+                    bindings::Gecko_FontSlantStyle_SetOblique(s, angle.0.degrees())
+                }
+            }
+        }
     }
     ${impl_simple_copy('font_style', 'mFont.style')}
     pub fn clone_font_style(&self) -> longhands::font_style::computed_value::T {
         use values::computed::font::FontStyle;
         FontStyle::from_gecko(self.gecko.mFont.style)
     }
 
     ${impl_simple_type_with_conversion("font_synthesis", "mFont.synthesis")}
--- a/servo/components/style/properties/longhand/font.mako.rs
+++ b/servo/components/style/properties/longhand/font.mako.rs
@@ -345,17 +345,19 @@ https://drafts.csswg.org/css-fonts-4/#lo
                     bindings::Gecko_nsFont_InitSystem(
                         &mut system,
                         id as i32,
                         cx.style().get_font().gecko(),
                         cx.device().pres_context()
                     )
                 }
                 let font_weight = longhands::font_weight::computed_value::T::from_gecko_weight(system.weight);
-                let font_stretch = NonNegative(Percentage(system.stretch as f32));
+                let font_stretch = NonNegative(Percentage(unsafe {
+                    bindings::Gecko_FontStretch_ToFloat(system.stretch)
+                }));
                 let font_style = FontStyle::from_gecko(system.style);
                 let ret = ComputedSystemFont {
                     font_family: longhands::font_family::computed_value::T(
                         FontFamilyList(
                             unsafe { system.fontlist.mFontlist.mBasePtr.to_safe() }
                         )
                     ),
                     font_size: FontSize {
--- a/servo/components/style/values/computed/font.rs
+++ b/servo/components/style/values/computed/font.rs
@@ -871,26 +871,30 @@ impl FontStyle {
     #[inline]
     fn default_angle() -> FontStyleAngle {
         FontStyleAngle(Angle::Deg(specified::DEFAULT_FONT_STYLE_OBLIQUE_ANGLE_DEGREES))
     }
 
 
     /// Get the font style from Gecko's nsFont struct.
     #[cfg(feature = "gecko")]
-    pub fn from_gecko(kw: u8) -> Self {
-        use gecko_bindings::structs;
-
-        match kw as u32 {
-            structs::NS_STYLE_FONT_STYLE_NORMAL => generics::FontStyle::Normal,
-            structs::NS_STYLE_FONT_STYLE_ITALIC => generics::FontStyle::Italic,
-            // FIXME(emilio): Grab the angle when we honor it :)
-            structs::NS_STYLE_FONT_STYLE_OBLIQUE => generics::FontStyle::Oblique(Self::default_angle()),
-            _ => unreachable!("Unknown font style"),
+    pub fn from_gecko(style: structs::FontSlantStyle) -> Self {
+        let mut angle = 0.;
+        let mut italic = false;
+        let mut normal = false;
+        unsafe {
+            bindings::Gecko_FontSlantStyle_Get(style, &mut normal, &mut italic, &mut angle);
         }
+        if normal {
+            return generics::FontStyle::Normal;
+        }
+        if italic {
+            return generics::FontStyle::Italic;
+        }
+        generics::FontStyle::Oblique(FontStyleAngle(Angle::Deg(angle)))
     }
 }
 
 impl ToCss for FontStyle {
     fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
     where
         W: fmt::Write,
     {
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -3796,16 +3796,17 @@ pub unsafe extern "C" fn Servo_Declarati
 pub extern "C" fn Servo_DeclarationBlock_SetKeywordValue(
     declarations: RawServoDeclarationBlockBorrowed,
     property: nsCSSPropertyID,
     value: i32
 ) {
     use style::properties::{PropertyDeclaration, LonghandId};
     use style::properties::longhands;
     use style::values::specified::BorderStyle;
+    use style::values::generics::font::FontStyle;
 
     let long = get_longhand_from_id!(property);
     let value = value as u32;
 
     let prop = match_wrap_declared! { long,
         MozUserModify => longhands::_moz_user_modify::SpecifiedValue::from_gecko_keyword(value),
         // TextEmphasisPosition => FIXME implement text-emphasis-position
         Direction => longhands::direction::SpecifiedValue::from_gecko_keyword(value),
@@ -3815,17 +3816,24 @@ pub extern "C" fn Servo_DeclarationBlock
         TextAlign => longhands::text_align::SpecifiedValue::from_gecko_keyword(value),
         TextEmphasisPosition => longhands::text_emphasis_position::SpecifiedValue::from_gecko_keyword(value),
         Clear => longhands::clear::SpecifiedValue::from_gecko_keyword(value),
         FontSize => {
             // We rely on Gecko passing in font-size values (0...7) here.
             longhands::font_size::SpecifiedValue::from_html_size(value as u8)
         },
         FontStyle => {
-            ToComputedValue::from_computed_value(&longhands::font_style::computed_value::T::from_gecko(value as u8))
+            let val = if value == structs::NS_FONT_STYLE_ITALIC {
+                FontStyle::Italic
+            } else {
+                debug_assert_eq!(value, structs::NS_FONT_STYLE_NORMAL);
+                FontStyle::Normal
+            };
+
+            ToComputedValue::from_computed_value(&val)
         },
         FontWeight => longhands::font_weight::SpecifiedValue::from_gecko_keyword(value),
         ListStyleType => Box::new(longhands::list_style_type::SpecifiedValue::from_gecko_keyword(value)),
         MozMathVariant => longhands::_moz_math_variant::SpecifiedValue::from_gecko_keyword(value),
         WhiteSpace => longhands::white_space::SpecifiedValue::from_gecko_keyword(value),
         CaptionSide => longhands::caption_side::SpecifiedValue::from_gecko_keyword(value),
         BorderTopStyle => BorderStyle::from_gecko_keyword(value),
         BorderRightStyle => BorderStyle::from_gecko_keyword(value),
@@ -5429,26 +5437,26 @@ pub extern "C" fn Servo_ParseFontShortha
     };
 
     // The system font is not acceptable, so we return false.
     let family = unsafe { &mut *family };
     match font.font_family {
         FontFamily::Values(list) => family.set_move(list.0),
         FontFamily::System(_) => return false,
     }
+
     let specified_font_style = match font.font_style {
         FontStyle::Specified(ref s) => s,
         FontStyle::System(_) => return false,
     };
-
     match *specified_font_style {
         GenericFontStyle::Normal => style.set_normal(),
         GenericFontStyle::Italic => style.set_enum(structs::NS_FONT_STYLE_ITALIC as i32),
         GenericFontStyle::Oblique(ref angle) => {
-            style.set_angle(SpecifiedFontStyle::compute_angle(angle))
+            style.set_font_style(SpecifiedFontStyle::compute_angle(angle).degrees())
         }
     }
 
     if font.font_stretch.get_system().is_some() {
         return false;
     }
     stretch.set_from(&font.font_stretch);
 
--- a/widget/android/nsLookAndFeel.cpp
+++ b/widget/android/nsLookAndFeel.cpp
@@ -461,19 +461,19 @@ nsLookAndFeel::GetFloatImpl(FloatID aID,
 
 /*virtual*/
 bool
 nsLookAndFeel::GetFontImpl(FontID aID, nsString& aFontName,
                            gfxFontStyle& aFontStyle,
                            float aDevPixPerCSSPixel)
 {
     aFontName.AssignLiteral("\"Roboto\"");
-    aFontStyle.style = NS_FONT_STYLE_NORMAL;
+    aFontStyle.style = FontSlantStyle::Normal();
     aFontStyle.weight = FontWeight::Normal();
-    aFontStyle.stretch = NS_FONT_STRETCH_NORMAL;
+    aFontStyle.stretch = FontStretch::Normal();
     aFontStyle.size = 9.0 * 96.0f / 72.0f * aDevPixPerCSSPixel;
     aFontStyle.systemFont = true;
     return true;
 }
 
 /*virtual*/
 bool
 nsLookAndFeel::GetEchoPasswordImpl()
--- a/widget/cocoa/nsLookAndFeel.mm
+++ b/widget/cocoa/nsLookAndFeel.mm
@@ -560,19 +560,19 @@ bool
 nsLookAndFeel::GetFontImpl(FontID aID, nsString &aFontName,
                            gfxFontStyle &aFontStyle,
                            float aDevPixPerCSSPixel)
 {
     NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
 
     // hack for now
     if (aID == eFont_Window || aID == eFont_Document) {
-        aFontStyle.style      = NS_FONT_STYLE_NORMAL;
+        aFontStyle.style      = mozilla::FontSlantStyle::Normal();
         aFontStyle.weight     = mozilla::FontWeight::Normal();
-        aFontStyle.stretch    = NS_FONT_STRETCH_NORMAL;
+        aFontStyle.stretch    = mozilla::FontStretch::Normal();
         aFontStyle.size       = 14 * aDevPixPerCSSPixel;
         aFontStyle.systemFont = true;
 
         aFontName.AssignLiteral("sans-serif");
         return true;
     }
 
     gfxPlatformMac::LookupSystemFont(aID, aFontName, aFontStyle,
--- a/widget/gtk/nsLookAndFeel.cpp
+++ b/widget/gtk/nsLookAndFeel.cpp
@@ -704,17 +704,17 @@ nsLookAndFeel::GetFloatImpl(FloatID aID,
     return res;
 }
 
 static void
 GetSystemFontInfo(GtkStyleContext *aStyle,
                   nsString *aFontName,
                   gfxFontStyle *aFontStyle)
 {
-    aFontStyle->style       = NS_FONT_STYLE_NORMAL;
+    aFontStyle->style = FontSlantStyle::Normal();
 
     // As in
     // https://git.gnome.org/browse/gtk+/tree/gtk/gtkwidget.c?h=3.22.19#n10333
     PangoFontDescription *desc;
     gtk_style_context_get(aStyle, gtk_style_context_get_state(aStyle),
                           "font", &desc, nullptr);
 
     aFontStyle->systemFont = true;
@@ -722,17 +722,17 @@ GetSystemFontInfo(GtkStyleContext *aStyl
     NS_NAMED_LITERAL_STRING(quote, "\"");
     NS_ConvertUTF8toUTF16 family(pango_font_description_get_family(desc));
     *aFontName = quote + family + quote;
 
     aFontStyle->weight =
         mozilla::FontWeight(pango_font_description_get_weight(desc));
 
     // FIXME: Set aFontStyle->stretch correctly!
-    aFontStyle->stretch = NS_FONT_STRETCH_NORMAL;
+    aFontStyle->stretch = FontStretch::Normal();
 
     float size = float(pango_font_description_get_size(desc)) / PANGO_SCALE;
 
     // |size| is now either pixels or pango-points (not Mozilla-points!)
 
     if (!pango_font_description_get_size_is_absolute(desc)) {
         // |size| is in pango-points, so convert to pixels.
         size *= float(gfxPlatformGtk::GetFontScaleDPI()) / POINTS_PER_INCH_FLOAT;
--- a/widget/headless/HeadlessLookAndFeelGTK.cpp
+++ b/widget/headless/HeadlessLookAndFeelGTK.cpp
@@ -332,19 +332,19 @@ HeadlessLookAndFeel::GetFloatImpl(FloatI
 }
 
 bool
 HeadlessLookAndFeel::GetFontImpl(FontID aID, nsString& aFontName,
                gfxFontStyle& aFontStyle,
                float aDevPixPerCSSPixel)
 {
   // Default to san-serif for everything.
-  aFontStyle.style      = NS_FONT_STYLE_NORMAL;
+  aFontStyle.style      = FontSlantStyle::Normal();
   aFontStyle.weight     = FontWeight::Normal();
-  aFontStyle.stretch    = NS_FONT_STRETCH_NORMAL;
+  aFontStyle.stretch    = FontStretch::Normal();
   aFontStyle.size       = 14 * aDevPixPerCSSPixel;
   aFontStyle.systemFont = true;
 
   aFontName.AssignLiteral("sans-serif");
   return true;
 }
 
 char16_t
--- a/widget/uikit/nsLookAndFeel.mm
+++ b/widget/uikit/nsLookAndFeel.mm
@@ -396,19 +396,19 @@ nsLookAndFeel::GetFloatImpl(FloatID aID,
 
 bool
 nsLookAndFeel::GetFontImpl(FontID aID, nsString &aFontName,
                            gfxFontStyle &aFontStyle,
                            float aDevPixPerCSSPixel)
 {
     // hack for now
     if (aID == eFont_Window || aID == eFont_Document) {
-        aFontStyle.style      = NS_FONT_STYLE_NORMAL;
+        aFontStyle.style      = FontSlantStyle::Normal();
         aFontStyle.weight     = FontWeight::Normal();
-        aFontStyle.stretch    = NS_FONT_STRETCH_NORMAL;
+        aFontStyle.stretch    = FontStretch::Normal();
         aFontStyle.size       = 14 * aDevPixPerCSSPixel;
         aFontStyle.systemFont = true;
 
         aFontName.AssignLiteral("sans-serif");
         return true;
     }
 
     //TODO: implement more here?
--- a/widget/windows/nsLookAndFeel.cpp
+++ b/widget/windows/nsLookAndFeel.cpp
@@ -698,25 +698,25 @@ GetSysFontInfo(HDC aHDC, LookAndFeel::Fo
   // system (cp936), but leave other sizes alone.
   if (pixelHeight < 12 && ::GetACP() == 936)
     pixelHeight = 12;
 
   aFontStyle.size = pixelHeight;
 
   // FIXME: What about oblique?
   aFontStyle.style =
-    (ptrLogFont->lfItalic) ? NS_FONT_STYLE_ITALIC : NS_FONT_STYLE_NORMAL;
+    (ptrLogFont->lfItalic) ? FontSlantStyle::Italic() : FontSlantStyle::Normal();
 
   // FIXME: Other weights?
   aFontStyle.weight =
     (ptrLogFont->lfWeight == FW_BOLD ?
         FontWeight::Bold() : FontWeight::Normal());
 
   // FIXME: Set aFontStyle->stretch correctly!
-  aFontStyle.stretch = NS_FONT_STRETCH_NORMAL;
+  aFontStyle.stretch = FontStretch::Normal();
 
   aFontStyle.systemFont = true;
 
   if (useShellDlg) {
     aFontName = NS_LITERAL_STRING("MS Shell Dlg 2");
   } else {
     memcpy(name, ptrLogFont->lfFaceName, LF_FACESIZE*sizeof(char16_t));
     aFontName = name;