Bug 1496486 - Remove nsCSSValue usage from font code. r=heycam
☠☠ backed out by be1729663405 ☠ ☠
authorEmilio Cobos Álvarez <emilio@crisal.io>
Wed, 03 Oct 2018 23:50:21 +0200
changeset 495986 86382b2249f6eab5f660e6e6c3aea69909e7f956
parent 495985 ab92ed3e0a2369a5a1764ba8e496e8f186fdbcd1
child 495987 8e465202c355f19b05fb741ef0be74afab6a6842
push id9984
push userffxbld-merge
push dateMon, 15 Oct 2018 21:07:35 +0000
treeherdermozilla-beta@183d27ea8570 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1496486
milestone64.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 1496486 - Remove nsCSSValue usage from font code. r=heycam Really sorry for the size of the patch. Differential Revision: https://phabricator.services.mozilla.com/D7753
gfx/src/FontPropertyTypes.h
gfx/thebes/gfxFontConstants.h
gfx/thebes/gfxUserFontSet.cpp
gfx/thebes/gfxUserFontSet.h
layout/base/nsLayoutUtils.cpp
layout/style/FontFace.cpp
layout/style/FontFace.h
layout/style/FontFaceSet.cpp
layout/style/FontFaceSet.h
layout/style/ServoBindingList.h
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
layout/style/ServoBindings.toml
layout/style/ServoCSSParser.cpp
layout/style/ServoCSSParser.h
layout/style/nsCSSValue.cpp
layout/style/nsCSSValue.h
layout/style/nsFontFaceLoader.cpp
layout/style/nsFontFaceLoader.h
layout/style/test/test_font_face_cascade.html
layout/style/test/test_font_loading_api.html
servo/components/style/cbindgen.toml
servo/components/style/font_face.rs
servo/components/style/gecko/rules.rs
servo/components/style/gecko_bindings/sugar/ns_css_value.rs
servo/components/style/values/computed/font.rs
servo/components/style/values/computed/percentage.rs
servo/components/style/values/specified/font.rs
servo/ports/geckolib/glue.rs
--- a/gfx/src/FontPropertyTypes.h
+++ b/gfx/src/FontPropertyTypes.h
@@ -270,16 +270,26 @@ public:
   {
     return FontStretch(kExtraExpanded);
   }
   static FontStretch UltraExpanded()
   {
     return FontStretch(kUltraExpanded);
   }
 
+  // The style system represents percentages in the 0.0..1.0 range, and
+  // FontStretch does it in the 0.0..100.0 range.
+  //
+  // TODO(emilio): We should consider changing this class to deal with the same
+  // range as the style system.
+  static FontStretch FromStyle(float aStylePercentage)
+  {
+    return FontStretch(std::min(aStylePercentage * 100.0f, float(kMax)));
+  }
+
   bool IsNormal() const { return mValue == kNormal; }
   float Percentage() const { return ToFloat(); }
 
   typedef uint16_t InternalType;
 
 private:
   friend class StretchRange;
 
--- a/gfx/thebes/gfxFontConstants.h
+++ b/gfx/thebes/gfxFontConstants.h
@@ -36,22 +36,16 @@
 
 #define NS_FONT_KERNING_AUTO                        0
 #define NS_FONT_KERNING_NONE                        1
 #define NS_FONT_KERNING_NORMAL                      2
 
 #define NS_FONT_SYNTHESIS_WEIGHT                    0x1
 #define NS_FONT_SYNTHESIS_STYLE                     0x2
 
-#define NS_FONT_DISPLAY_AUTO            0
-#define NS_FONT_DISPLAY_BLOCK           1
-#define NS_FONT_DISPLAY_SWAP            2
-#define NS_FONT_DISPLAY_FALLBACK        3
-#define NS_FONT_DISPLAY_OPTIONAL        4
-
 #define NS_FONT_OPTICAL_SIZING_AUTO     0
 #define NS_FONT_OPTICAL_SIZING_NONE     1
 
 #define NS_FONT_VARIANT_ALTERNATES_NORMAL             0
 // alternates - simple enumerated values
 #define NS_FONT_VARIANT_ALTERNATES_HISTORICAL        (1 << 0)
 
 // alternates - values that use functional syntax
--- a/gfx/thebes/gfxUserFontSet.cpp
+++ b/gfx/thebes/gfxUserFontSet.cpp
@@ -107,17 +107,17 @@ gfxUserFontEntry::gfxUserFontEntry(gfxUs
              const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
              WeightRange aWeight,
              StretchRange aStretch,
              SlantStyleRange aStyle,
              const nsTArray<gfxFontFeature>& aFeatureSettings,
              const nsTArray<gfxFontVariation>& aVariationSettings,
              uint32_t aLanguageOverride,
              gfxCharacterMap* aUnicodeRanges,
-             uint8_t aFontDisplay,
+             StyleFontDisplay aFontDisplay,
              RangeFlags aRangeFlags)
     : gfxFontEntry(NS_LITERAL_CSTRING("userfont")),
       mUserFontLoadState(STATUS_NOT_LOADED),
       mFontDataLoadingState(NOT_LOADING),
       mUnsupportedFormat(false),
       mFontDisplay(aFontDisplay),
       mLoader(nullptr),
       mFontSet(aFontSet)
@@ -147,17 +147,17 @@ bool
 gfxUserFontEntry::Matches(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                           WeightRange aWeight,
                           StretchRange aStretch,
                           SlantStyleRange aStyle,
                           const nsTArray<gfxFontFeature>& aFeatureSettings,
                           const nsTArray<gfxFontVariation>& aVariationSettings,
                           uint32_t aLanguageOverride,
                           gfxCharacterMap* aUnicodeRanges,
-                          uint8_t aFontDisplay,
+                          StyleFontDisplay aFontDisplay,
                           RangeFlags aRangeFlags)
 {
     return Weight() == aWeight &&
            Stretch() == aStretch &&
            SlantStyle() == aStyle &&
            mFeatureSettings == aFeatureSettings &&
            mVariationSettings == aVariationSettings &&
            mLanguageOverride == aLanguageOverride &&
@@ -948,17 +948,17 @@ gfxUserFontSet::FindOrCreateUserFontEntr
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                                WeightRange aWeight,
                                StretchRange aStretch,
                                SlantStyleRange aStyle,
                                const nsTArray<gfxFontFeature>& aFeatureSettings,
                                const nsTArray<gfxFontVariation>& aVariationSettings,
                                uint32_t aLanguageOverride,
                                gfxCharacterMap* aUnicodeRanges,
-                               uint8_t aFontDisplay,
+                               StyleFontDisplay aFontDisplay,
                                RangeFlags aRangeFlags)
 {
     RefPtr<gfxUserFontEntry> entry;
 
     // If there's already a userfont entry in the family whose descriptors all match,
     // we can just move it to the end of the list instead of adding a new
     // face that will always "shadow" the old one.
     // Note that we can't do this for platform font entries, even if the
@@ -991,17 +991,17 @@ gfxUserFontSet::FindExistingUserFontEntr
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                                WeightRange aWeight,
                                StretchRange aStretch,
                                SlantStyleRange aStyle,
                                const nsTArray<gfxFontFeature>& aFeatureSettings,
                                const nsTArray<gfxFontVariation>& aVariationSettings,
                                uint32_t aLanguageOverride,
                                gfxCharacterMap* aUnicodeRanges,
-                               uint8_t aFontDisplay,
+                               StyleFontDisplay aFontDisplay,
                                RangeFlags aRangeFlags)
 {
     nsTArray<RefPtr<gfxFontEntry>>& fontList = aFamily->GetFontList();
 
     for (size_t i = 0, count = fontList.Length(); i < count; i++) {
         if (!fontList[i]->mIsUserFontContainer) {
             continue;
         }
@@ -1037,17 +1037,17 @@ gfxUserFontSet::AddUserFontEntry(const n
         aUserFontEntry->Stretch().ToString(stretchString);
         LOG(("userfonts (%p) added to \"%s\" (%p) style: %s weight: %s "
              "stretch: %s display: %d",
              this, aFamilyName.get(), aUserFontEntry,
              (aUserFontEntry->IsItalic() ? "italic" :
               (aUserFontEntry->IsOblique() ? "oblique" : "normal")),
              weightString.get(),
              stretchString.get(),
-             aUserFontEntry->GetFontDisplay()));
+             static_cast<int>(aUserFontEntry->GetFontDisplay())));
     }
 }
 
 void
 gfxUserFontSet::IncrementGeneration(bool aIsRebuild)
 {
     // add one, increment again if zero
     ++sFontSetGeneration;
--- a/gfx/thebes/gfxUserFontSet.h
+++ b/gfx/thebes/gfxUserFontSet.h
@@ -239,32 +239,32 @@ public:
                               const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                               WeightRange aWeight,
                               StretchRange aStretch,
                               SlantStyleRange aStyle,
                               const nsTArray<gfxFontFeature>& aFeatureSettings,
                               const nsTArray<gfxFontVariation>& aVariationSettings,
                               uint32_t aLanguageOverride,
                               gfxCharacterMap* aUnicodeRanges,
-                              uint8_t aFontDisplay,
+                              mozilla::StyleFontDisplay aFontDisplay,
                               RangeFlags aRangeFlags) = 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 nsACString& aFamilyName,
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                                WeightRange aWeight,
                                StretchRange aStretch,
                                SlantStyleRange aStyle,
                                const nsTArray<gfxFontFeature>& aFeatureSettings,
                                const nsTArray<gfxFontVariation>& aVariationSettings,
                                uint32_t aLanguageOverride,
                                gfxCharacterMap* aUnicodeRanges,
-                               uint8_t aFontDisplay,
+                               mozilla::StyleFontDisplay aFontDisplay,
                                RangeFlags aRangeFlags);
 
     // add in a font face for which we have the gfxUserFontEntry already
     void AddUserFontEntry(const nsCString& aFamilyName,
                           gfxUserFontEntry* aUserFontEntry);
 
     // Whether there is a face with this family name
     bool HasFamily(const nsACString& aFamilyName) const
@@ -510,17 +510,17 @@ protected:
                                    const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                                    WeightRange aWeight,
                                    StretchRange aStretch,
                                    SlantStyleRange aStyle,
                                    const nsTArray<gfxFontFeature>& aFeatureSettings,
                                    const nsTArray<gfxFontVariation>& aVariationSettings,
                                    uint32_t aLanguageOverride,
                                    gfxCharacterMap* aUnicodeRanges,
-                                   uint8_t aFontDisplay,
+                                   mozilla::StyleFontDisplay aFontDisplay,
                                    RangeFlags aRangeFlags);
 
     // creates a new gfxUserFontFamily in mFontFamilies, or returns an existing
     // family if there is one
     gfxUserFontFamily* GetFamily(const nsACString& aFamilyName);
 
     // font families defined by @font-face rules
     nsRefPtrHashtable<nsCStringHashKey, gfxUserFontFamily> mFontFamilies;
@@ -561,31 +561,31 @@ public:
                      const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                      WeightRange aWeight,
                      StretchRange aStretch,
                      SlantStyleRange aStyle,
                      const nsTArray<gfxFontFeature>& aFeatureSettings,
                      const nsTArray<gfxFontVariation>& aVariationSettings,
                      uint32_t aLanguageOverride,
                      gfxCharacterMap* aUnicodeRanges,
-                     uint8_t aFontDisplay,
+                     mozilla::StyleFontDisplay aFontDisplay,
                      RangeFlags aRangeFlags);
 
     virtual ~gfxUserFontEntry();
 
     // Return whether the entry matches the given list of attributes
     bool Matches(const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                  WeightRange aWeight,
                  StretchRange aStretch,
                  SlantStyleRange aStyle,
                  const nsTArray<gfxFontFeature>& aFeatureSettings,
                  const nsTArray<gfxFontVariation>& aVariationSettings,
                  uint32_t aLanguageOverride,
                  gfxCharacterMap* aUnicodeRanges,
-                 uint8_t aFontDisplay,
+                 mozilla::StyleFontDisplay aFontDisplay,
                  RangeFlags aRangeFlags);
 
     gfxFont* CreateFontInstance(const gfxFontStyle* aFontStyle) override;
 
     gfxFontEntry* GetPlatformFontEntry() const { return mPlatformFontEntry; }
 
     // is the font loading or loaded, or did it fail?
     UserFontLoadState LoadState() const { return mUserFontLoadState; }
@@ -612,17 +612,17 @@ public:
         }
         return true;
     }
 
     gfxCharacterMap* GetUnicodeRangeMap() const {
         return mCharacterMap.get();
     }
 
-    uint8_t GetFontDisplay() const { return mFontDisplay; }
+    mozilla::StyleFontDisplay GetFontDisplay() const { return mFontDisplay; }
 
     // load the font - starts the loading of sources which continues until
     // a valid font resource is found or all sources fail
     void Load();
 
     // methods to expose some information to FontFaceSet::UserFontSet
     // since we can't make that class a friend
     void SetLoader(nsFontFaceLoader* aLoader) { mLoader = aLoader; }
@@ -717,18 +717,18 @@ protected:
                              // so keep hiding fallback font
         LOADING_SLOWLY,      // timeout happened and we're not nearly done,
                              // so use the fallback font
         LOADING_TIMED_OUT,   // font load took too long
         LOADING_FAILED       // failed to load any source: use fallback
     };
     FontDataLoadingState     mFontDataLoadingState;
 
-    bool                     mUnsupportedFormat;
-    uint8_t                  mFontDisplay; // timing of userfont fallback
+    bool mUnsupportedFormat;
+    mozilla::StyleFontDisplay mFontDisplay; // timing of userfont fallback
 
     RefPtr<gfxFontEntry>   mPlatformFontEntry;
     nsTArray<gfxFontFaceSrc> mSrcList;
     uint32_t                 mSrcIndex; // index of loading src item
     // This field is managed by the nsFontFaceLoader. In the destructor and Cancel()
     // methods of nsFontFaceLoader this reference is nulled out.
     nsFontFaceLoader* MOZ_NON_OWNING_REF mLoader; // current loader for this entry, if any
     gfxUserFontSet*   MOZ_NON_OWNING_REF mFontSet; // font-set which owns this userfont entry
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -10120,110 +10120,16 @@ nsLayoutUtils::ComputeSystemFont(nsFont*
       aSystemFont->size =
         std::max(aDefaultVariableFont->size -
                  nsPresContext::CSSPointsToAppUnits(2), 0);
     }
 #endif
   }
 }
 
-static inline void
-AssertValidFontTag(const nsString& aString)
-{
-  // To be valid as a font feature tag, a string MUST be:
-  MOZ_ASSERT(aString.Length() == 4 &&              // (1) exactly 4 chars long
-             NS_IsAscii(aString.BeginReading()) && // (2) entirely ASCII
-             isprint(aString[0]) &&                // (3) all printable chars
-             isprint(aString[1]) &&
-             isprint(aString[2]) &&
-             isprint(aString[3]));
-}
-
-/* static */ void
-nsLayoutUtils::ComputeFontFeatures(const nsCSSValuePairList *aFeaturesList,
-                                   nsTArray<gfxFontFeature>& aFeatureSettings)
-{
-  aFeatureSettings.Clear();
-  for (const nsCSSValuePairList* p = aFeaturesList; p; p = p->mNext) {
-    gfxFontFeature feat;
-
-    MOZ_ASSERT(aFeaturesList->mXValue.GetUnit() == eCSSUnit_String,
-               "unexpected value unit");
-
-    // tag is a 4-byte ASCII sequence
-    nsAutoString tag;
-    p->mXValue.GetStringValue(tag);
-    AssertValidFontTag(tag);
-    if (tag.Length() != 4) {
-      continue;
-    }
-    // parsing validates that these are ASCII chars
-    // tags are always big-endian
-    feat.mTag = (tag[0] << 24) | (tag[1] << 16) | (tag[2] << 8)  | tag[3];
-
-    // value
-    NS_ASSERTION(p->mYValue.GetUnit() == eCSSUnit_Integer,
-                 "should have found an integer unit");
-    feat.mValue = p->mYValue.GetIntValue();
-
-    aFeatureSettings.AppendElement(feat);
-  }
-}
-
-/* static */ void
-nsLayoutUtils::ComputeFontVariations(const nsCSSValuePairList* aVariationsList,
-                                     nsTArray<gfxFontVariation>& aVariationSettings)
-{
-  aVariationSettings.Clear();
-  for (const nsCSSValuePairList* p = aVariationsList; p; p = p->mNext) {
-    gfxFontVariation var;
-
-    MOZ_ASSERT(aVariationsList->mXValue.GetUnit() == eCSSUnit_String,
-               "unexpected value unit");
-
-    // tag is a 4-byte ASCII sequence
-    nsAutoString tag;
-    p->mXValue.GetStringValue(tag);
-    AssertValidFontTag(tag);
-    if (tag.Length() != 4) {
-      continue;
-    }
-    // parsing validates that these are ASCII chars
-    // tags are always big-endian
-    var.mTag = (tag[0] << 24) | (tag[1] << 16) | (tag[2] << 8)  | tag[3];
-
-    // value
-    NS_ASSERTION(p->mYValue.GetUnit() == eCSSUnit_Number,
-                 "should have found a number unit");
-    var.mValue = p->mYValue.GetFloatValue();
-
-    aVariationSettings.AppendElement(var);
-  }
-}
-
-/* static */ uint32_t
-nsLayoutUtils::ParseFontLanguageOverride(const nsAString& aLangTag)
-{
-  if (!aLangTag.Length() || aLangTag.Length() > 4) {
-    return NO_FONT_LANGUAGE_OVERRIDE;
-  }
-  uint32_t index, result = 0;
-  for (index = 0; index < aLangTag.Length(); ++index) {
-    char16_t ch = aLangTag[index];
-    if (!nsCRT::IsAscii(ch)) { // valid tags are pure ASCII
-      return NO_FONT_LANGUAGE_OVERRIDE;
-    }
-    result = (result << 8) + ch;
-  }
-  while (index++ < 4) {
-    result = (result << 8) + 0x20;
-  }
-  return result;
-}
-
 /* static */ bool
 nsLayoutUtils::ShouldHandleMetaViewport(nsIDocument* aDocument)
 {
   uint32_t metaViewportOverride = nsIDocShell::META_VIEWPORT_OVERRIDE_NONE;
   if (aDocument) {
     if (nsIDocShell* docShell = aDocument->GetDocShell()) {
       docShell->GetMetaViewportOverride(&metaViewportOverride);
     }
--- a/layout/style/FontFace.cpp
+++ b/layout/style/FontFace.cpp
@@ -218,33 +218,17 @@ FontFace::InitializeSource(const StringO
   SetStatus(FontFaceLoadStatus::Loading);
   DoLoad();
 }
 
 void
 FontFace::GetFamily(nsString& aResult)
 {
   mFontFaceSet->FlushUserFontSet();
-
-  // Serialize the same way as in nsCSSFontFaceStyleDecl::GetPropertyValue.
-  nsCSSValue value;
-  GetDesc(eCSSFontDesc_Family, value);
-
-  aResult.Truncate();
-
-  if (value.GetUnit() == eCSSUnit_Null) {
-    return;
-  }
-
-  nsDependentString family(value.GetStringBufferValue());
-  if (!family.IsEmpty()) {
-    // The string length can be zero when the author passed an invalid
-    // family name or an invalid descriptor to the JS FontFace constructor.
-    nsStyleUtil::AppendEscapedCSSString(family, aResult);
-  }
+  GetDesc(eCSSFontDesc_Family, aResult);
 }
 
 void
 FontFace::SetFamily(const nsAString& aValue, ErrorResult& aRv)
 {
   mFontFaceSet->FlushUserFontSet();
   SetDescriptor(eCSSFontDesc_Family, aValue, aRv);
 }
@@ -290,20 +274,16 @@ FontFace::SetStretch(const nsAString& aV
   mFontFaceSet->FlushUserFontSet();
   SetDescriptor(eCSSFontDesc_Stretch, aValue, aRv);
 }
 
 void
 FontFace::GetUnicodeRange(nsString& aResult)
 {
   mFontFaceSet->FlushUserFontSet();
-
-  // There is no eCSSProperty_unicode_range for us to pass in to GetDesc
-  // to get a serialized (possibly defaulted) value, but that function
-  // doesn't use the property ID for this descriptor anyway.
   GetDesc(eCSSFontDesc_UnicodeRange, aResult);
 }
 
 void
 FontFace::SetUnicodeRange(const nsAString& aValue, ErrorResult& aRv)
 {
   mFontFaceSet->FlushUserFontSet();
   SetDescriptor(eCSSFontDesc_UnicodeRange, aValue, aRv);
@@ -602,23 +582,16 @@ FontFace::SetDescriptors(const nsAString
     SetStatus(FontFaceLoadStatus::Error);
     return false;
   }
 
   return true;
 }
 
 void
-FontFace::GetDesc(nsCSSFontDesc aDescID, nsCSSValue& aResult) const
-{
-  aResult.Reset();
-  Servo_FontFaceRule_GetDescriptor(GetData(), aDescID, &aResult);
-}
-
-void
 FontFace::GetDesc(nsCSSFontDesc aDescID, nsString& aResult) const
 {
   aResult.Truncate();
   Servo_FontFaceRule_GetDescriptorCssText(GetData(), aDescID, &aResult);
 
   // Fill in a default value for missing descriptors.
   if (aResult.IsEmpty()) {
     if (aDescID == eCSSFontDesc_UnicodeRange) {
@@ -661,29 +634,101 @@ FontFace::SetUserFontEntry(gfxUserFontEn
     FontFaceLoadStatus newStatus =
       LoadStateToStatus(mUserFontEntry->LoadState());
     if (newStatus > mStatus) {
       SetStatus(newStatus);
     }
   }
 }
 
-bool
-FontFace::GetFamilyName(nsCString& aResult)
+Maybe<StyleComputedFontWeightRange>
+FontFace::GetFontWeight() const
+{
+  StyleComputedFontWeightRange range;
+  if (!Servo_FontFaceRule_GetFontWeight(GetData(), &range)) {
+    return Nothing();
+  }
+  return Some(range);
+}
+
+Maybe<StyleComputedFontStretchRange>
+FontFace::GetFontStretch() const
 {
-  nsCSSValue value;
-  GetDesc(eCSSFontDesc_Family, value);
+  StyleComputedFontStretchRange range;
+  if (!Servo_FontFaceRule_GetFontStretch(GetData(), &range)) {
+    return Nothing();
+  }
+  return Some(range);
+}
+
+Maybe<StyleComputedFontStyleDescriptor>
+FontFace::GetFontStyle() const
+{
+  StyleComputedFontStyleDescriptor descriptor;
+  if (!Servo_FontFaceRule_GetFontStyle(GetData(), &descriptor)) {
+    return Nothing();
+  }
+  return Some(descriptor);
+}
+
+Maybe<StyleFontDisplay>
+FontFace::GetFontDisplay() const
+{
+  StyleFontDisplay display;
+  if (!Servo_FontFaceRule_GetFontDisplay(GetData(), &display)) {
+    return Nothing();
+  }
+  return Some(display);
+}
 
-  if (value.GetUnit() == eCSSUnit_String) {
-    nsString familyname;
-    value.GetStringValue(familyname);
-    AppendUTF16toUTF8(familyname, aResult);
+Maybe<StyleFontLanguageOverride>
+FontFace::GetFontLanguageOverride() const
+{
+  StyleFontLanguageOverride langOverride;
+  if (!Servo_FontFaceRule_GetFontLanguageOverride(GetData(), &langOverride)) {
+    return Nothing();
+  }
+  return Some(langOverride);
+}
+
+bool
+FontFace::HasLocalSrc() const
+{
+  AutoTArray<StyleFontFaceSourceListComponent, 8> components;
+  GetSources(components);
+  for (auto& component : components) {
+    if (component.tag == StyleFontFaceSourceListComponent::Tag::Local) {
+      return true;
+    }
   }
+  return false;
+}
 
-  return !aResult.IsEmpty();
+void
+FontFace::GetFontFeatureSettings(nsTArray<gfxFontFeature>& aFeatures) const
+{
+  Servo_FontFaceRule_GetFeatureSettings(GetData(), &aFeatures);
+}
+
+void
+FontFace::GetFontVariationSettings(nsTArray<gfxFontVariation>& aVariations) const
+{
+  Servo_FontFaceRule_GetVariationSettings(GetData(), &aVariations);
+}
+
+void
+FontFace::GetSources(nsTArray<StyleFontFaceSourceListComponent>& aSources) const
+{
+  Servo_FontFaceRule_GetSources(GetData(), &aSources);
+}
+
+nsAtom*
+FontFace::GetFamilyName() const
+{
+  return Servo_FontFaceRule_GetFamilyName(GetData());
 }
 
 void
 FontFace::DisconnectFromRule()
 {
   MOZ_ASSERT(HasRule());
 
   // Make a copy of the descriptors.
@@ -790,29 +835,25 @@ FontFace::EnsurePromise()
 
 gfxCharacterMap*
 FontFace::GetUnicodeRangeAsCharacterMap()
 {
   if (!mUnicodeRangeDirty) {
     return mUnicodeRange;
   }
 
-  nsCSSValue val;
-  GetDesc(eCSSFontDesc_UnicodeRange, val);
+  size_t len;
+  const StyleUnicodeRange* rangesPtr =
+    Servo_FontFaceRule_GetUnicodeRanges(GetData(), &len);
 
-  if (val.GetUnit() == eCSSUnit_Array) {
+  Span<const StyleUnicodeRange> ranges(rangesPtr, len);
+  if (!ranges.IsEmpty()) {
     mUnicodeRange = new gfxCharacterMap();
-    const nsCSSValue::Array& sources = *val.GetArrayValue();
-    MOZ_ASSERT(sources.Count() % 2 == 0,
-               "odd number of entries in a unicode-range: array");
-
-    for (uint32_t i = 0; i < sources.Count(); i += 2) {
-      uint32_t min = sources[i].GetIntValue();
-      uint32_t max = sources[i+1].GetIntValue();
-      mUnicodeRange->SetRange(min, max);
+    for (auto& range : ranges) {
+      mUnicodeRange->SetRange(range.start, range.end);
     }
   } else {
     mUnicodeRange = nullptr;
   }
 
   mUnicodeRangeDirty = false;
   return mUnicodeRange;
 }
--- a/layout/style/FontFace.h
+++ b/layout/style/FontFace.h
@@ -4,16 +4,19 @@
  * 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 mozilla_dom_FontFace_h
 #define mozilla_dom_FontFace_h
 
 #include "mozilla/dom/FontFaceBinding.h"
 #include "mozilla/FontPropertyTypes.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/Pair.h"
+#include "mozilla/ServoStyleConsts.h"
 #include "gfxUserFontSet.h"
 #include "nsAutoPtr.h"
 #include "nsCSSPropertyID.h"
 #include "nsCSSValue.h"
 #include "nsWrapperCache.h"
 
 class gfxFontFaceBufferSource;
 struct RawServoFontFaceRule;
@@ -50,17 +53,17 @@ public:
           const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
           WeightRange aWeight,
           StretchRange aStretch,
           SlantStyleRange aStyle,
           const nsTArray<gfxFontFeature>& aFeatureSettings,
           const nsTArray<gfxFontVariation>& aVariationSettings,
           uint32_t aLanguageOverride,
           gfxCharacterMap* aUnicodeRanges,
-          uint8_t aFontDisplay,
+          StyleFontDisplay aFontDisplay,
           RangeFlags aRangeFlags)
       : gfxUserFontEntry(aFontSet, aFontFaceSrcList, aWeight, aStretch,
                          aStyle, aFeatureSettings, aVariationSettings,
                          aLanguageOverride,
                          aUnicodeRanges, aFontDisplay,
                          aRangeFlags) {}
 
     virtual void SetLoadState(UserFontLoadState aLoadState) override;
@@ -82,17 +85,25 @@ public:
   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
 
   static already_AddRefed<FontFace>
   CreateForRule(nsISupports* aGlobal, FontFaceSet* aFontFaceSet,
                 RawServoFontFaceRule* aRule);
 
   RawServoFontFaceRule* GetRule() { return mRule; }
 
-  void GetDesc(nsCSSFontDesc aDescID, nsCSSValue& aResult) const;
+  bool HasLocalSrc() const;
+  Maybe<StyleComputedFontWeightRange> GetFontWeight() const;
+  Maybe<StyleComputedFontStretchRange> GetFontStretch() const;
+  Maybe<StyleComputedFontStyleDescriptor> GetFontStyle() const;
+  Maybe<StyleFontDisplay> GetFontDisplay() const;
+  void GetFontFeatureSettings(nsTArray<gfxFontFeature>&) const;
+  void GetFontVariationSettings(nsTArray<gfxFontVariation>&) const;
+  void GetSources(nsTArray<StyleFontFaceSourceListComponent>&) const;
+  Maybe<StyleFontLanguageOverride> GetFontLanguageOverride() const;
 
   gfxUserFontEntry* CreateUserFontEntry();
   gfxUserFontEntry* GetUserFontEntry() const { return mUserFontEntry; }
   void SetUserFontEntry(gfxUserFontEntry* aEntry);
 
   /**
    * Returns whether this object is in the specified FontFaceSet.
    */
@@ -101,19 +112,19 @@ public:
   void AddFontFaceSet(FontFaceSet* aFontFaceSet);
   void RemoveFontFaceSet(FontFaceSet* aFontFaceSet);
 
   FontFaceSet* GetPrimaryFontFaceSet() const { return mFontFaceSet; }
 
   /**
    * Gets the family name of the FontFace as a raw string (such as 'Times', as
    * opposed to GetFamily, which returns a CSS-escaped string, such as
-   * '"Times"').  Returns whether a valid family name was available.
+   * '"Times"').  Returns null if a valid family name was not available.
    */
-  bool GetFamilyName(nsCString& aResult);
+  nsAtom* GetFamilyName() const;
 
   /**
    * Returns whether this object is CSS-connected, i.e. reflecting an
    * @font-face rule.
    */
   bool HasRule() const { return mRule; }
 
   /**
--- a/layout/style/FontFaceSet.cpp
+++ b/layout/style/FontFaceSet.cpp
@@ -206,53 +206,46 @@ void
 FontFaceSet::ParseFontShorthandForMatching(
                             const nsAString& aFont,
                             RefPtr<SharedFontList>& aFamilyList,
                             FontWeight& aWeight,
                             FontStretch& aStretch,
                             FontSlantStyle& aStyle,
                             ErrorResult& aRv)
 {
-  nsCSSValue style;
-  nsCSSValue stretch;
-  nsCSSValue weight;
+  StyleComputedFontStyleDescriptor style;
+  float stretch;
+  float 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:
+  switch (style.tag) {
+    case StyleComputedFontStyleDescriptor::Tag::Normal:
       aStyle = FontSlantStyle::Normal();
       break;
-    case eCSSUnit_Enumerated:
-      MOZ_ASSERT(style.GetIntValue() == NS_FONT_STYLE_ITALIC);
+    case StyleComputedFontStyleDescriptor::Tag::Italic:
       aStyle = FontSlantStyle::Italic();
       break;
-    case eCSSUnit_FontSlantStyle:
-      aStyle = style.GetFontSlantStyle();
+    case StyleComputedFontStyleDescriptor::Tag::Oblique:
+      MOZ_ASSERT(style.oblique._0 == style.oblique._1,
+                 "We use ComputedFontStyleDescriptor just for convenience, "
+                 "the two values should always match");
+      aStyle = FontSlantStyle::Oblique(style.oblique._0);
       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());
-  }
-
-  MOZ_ASSERT(stretch.GetUnit() == eCSSUnit_FontStretch);
-  aStretch = stretch.GetFontStretch();
+  aWeight = FontWeight(weight);
+  aStretch = FontStretch::FromStyle(stretch);
 }
 
 static bool
 HasAnyCharacterInUnicodeRange(gfxUserFontEntry* aEntry,
                               const nsAString& aInput)
 {
   const char16_t* p = aInput.Data();
   const char16_t* end = p + aInput.Length();
@@ -828,107 +821,94 @@ FontFaceSet::UpdateRules(const nsTArray<
          mUserFontSet.get(),
          (modified ? "modified" : "not modified"),
          (int)(mRuleFaces.Length())));
   }
 
   return modified;
 }
 
-static bool
-HasLocalSrc(const nsCSSValue::Array *aSrcArr)
-{
-  size_t numSrc = aSrcArr->Count();
-  for (size_t i = 0; i < numSrc; i++) {
-    if (aSrcArr->Item(i).GetUnit() == eCSSUnit_Local_Font) {
-      return true;
-    }
-  }
-  return false;
-}
-
 void
 FontFaceSet::IncrementGeneration(bool aIsRebuild)
 {
   MOZ_ASSERT(mUserFontSet);
   mUserFontSet->IncrementGeneration(aIsRebuild);
 }
 
 void
 FontFaceSet::InsertNonRuleFontFace(FontFace* aFontFace,
                                    bool& aFontSetModified)
 {
-  nsAutoCString fontfamily;
-  if (!aFontFace->GetFamilyName(fontfamily)) {
+  nsAtom* fontFamily = aFontFace->GetFamilyName();
+  if (!fontFamily) {
     // If there is no family name, this rule cannot contribute a
     // usable font, so there is no point in processing it further.
     return;
   }
 
+  nsAtomCString family(fontFamily);
+
   // Just create a new font entry if we haven't got one already.
   if (!aFontFace->GetUserFontEntry()) {
     // XXX Should we be checking mUserFontSet->mLocalRulesUsed like
     // InsertRuleFontFace does?
     RefPtr<gfxUserFontEntry> entry =
-      FindOrCreateUserFontEntryFromFontFace(fontfamily, aFontFace,
-                                            SheetType::Doc);
+      FindOrCreateUserFontEntryFromFontFace(family, aFontFace, SheetType::Doc);
     if (!entry) {
       return;
     }
     aFontFace->SetUserFontEntry(entry);
   }
 
   aFontSetModified = true;
-  mUserFontSet->AddUserFontEntry(fontfamily, aFontFace->GetUserFontEntry());
+  mUserFontSet->AddUserFontEntry(family, aFontFace->GetUserFontEntry());
 }
 
 void
 FontFaceSet::InsertRuleFontFace(FontFace* aFontFace, SheetType aSheetType,
                                 nsTArray<FontFaceRecord>& aOldRecords,
                                 bool& aFontSetModified)
 {
-  nsAutoCString fontfamily;
-  if (!aFontFace->GetFamilyName(fontfamily)) {
+  nsAtom* fontFamily = aFontFace->GetFamilyName();
+  if (!fontFamily) {
     // If there is no family name, this rule cannot contribute a
     // usable font, so there is no point in processing it further.
     return;
   }
 
   bool remove = false;
   size_t removeIndex;
 
+  nsAtomCString family(fontFamily);
+
   // This is a rule backed FontFace.  First, we check in aOldRecords; if
   // the FontFace for the rule exists there, just move it to the new record
   // list, and put the entry into the appropriate family.
   for (size_t i = 0; i < aOldRecords.Length(); ++i) {
     FontFaceRecord& rec = aOldRecords[i];
 
     if (rec.mFontFace == aFontFace &&
         rec.mSheetType == aSheetType) {
 
       // if local rules were used, don't use the old font entry
       // for rules containing src local usage
-      if (mUserFontSet->mLocalRulesUsed &&
-          mUserFontSet->mRebuildLocalRules) {
-        nsCSSValue val;
-        aFontFace->GetDesc(eCSSFontDesc_Src, val);
-        nsCSSUnit unit = val.GetUnit();
-        if (unit == eCSSUnit_Array && HasLocalSrc(val.GetArrayValue())) {
+      if (mUserFontSet->mLocalRulesUsed && mUserFontSet->mRebuildLocalRules) {
+        if (aFontFace->HasLocalSrc()) {
           // Remove the old record, but wait to see if we successfully create a
           // new user font entry below.
           remove = true;
           removeIndex = i;
           break;
         }
       }
 
       gfxUserFontEntry* entry = rec.mFontFace->GetUserFontEntry();
       MOZ_ASSERT(entry, "FontFace should have a gfxUserFontEntry by now");
 
-      mUserFontSet->AddUserFontEntry(fontfamily, entry);
+      mUserFontSet->AddUserFontEntry(family, entry);
 
       MOZ_ASSERT(!HasRuleFontFace(rec.mFontFace),
                  "FontFace should not occur in mRuleFaces twice");
 
       mRuleFaces.AppendElement(rec);
       aOldRecords.RemoveElementAt(i);
       // note the set has been modified if an old rule was skipped to find
       // this one - something has been dropped, or ordering changed
@@ -936,17 +916,17 @@ FontFaceSet::InsertRuleFontFace(FontFace
         aFontSetModified = true;
       }
       return;
     }
   }
 
   // this is a new rule:
   RefPtr<gfxUserFontEntry> entry =
-    FindOrCreateUserFontEntryFromFontFace(fontfamily, aFontFace, aSheetType);
+    FindOrCreateUserFontEntryFromFontFace(family, aFontFace, aSheetType);
 
   if (!entry) {
     return;
   }
 
   if (remove) {
     // Although we broke out of the aOldRecords loop above, since we found
     // src local usage, and we're not using the old user font entry, we still
@@ -974,202 +954,119 @@ FontFaceSet::InsertRuleFontFace(FontFace
   // this was a new rule and font entry, so note that the set was modified
   aFontSetModified = true;
 
   // Add the entry to the end of the list.  If an existing userfont entry was
   // returned by FindOrCreateUserFontEntryFromFontFace that was already stored
   // on the family, gfxUserFontFamily::AddFontEntry(), which AddUserFontEntry
   // calls, will automatically remove the earlier occurrence of the same
   // userfont entry.
-  mUserFontSet->AddUserFontEntry(fontfamily, entry);
+  mUserFontSet->AddUserFontEntry(family, entry);
 }
 
 /* static */ already_AddRefed<gfxUserFontEntry>
 FontFaceSet::FindOrCreateUserFontEntryFromFontFace(FontFace* aFontFace)
 {
-  nsAutoCString fontfamily;
-  if (!aFontFace->GetFamilyName(fontfamily)) {
+  nsAtom* fontFamily = aFontFace->GetFamilyName();
+  if (!fontFamily) {
     // If there is no family name, this rule cannot contribute a
     // usable font, so there is no point in processing it further.
     return nullptr;
   }
 
-  return FindOrCreateUserFontEntryFromFontFace(fontfamily, aFontFace,
+  return FindOrCreateUserFontEntryFromFontFace(nsAtomCString(fontFamily), aFontFace,
                                                SheetType::Doc);
 }
 
-static FontWeight
-GetWeightForDescriptor(const nsCSSValue& aVal)
-{
-  switch (aVal.GetUnit()) {
-    case eCSSUnit_FontWeight:
-      return aVal.GetFontWeight();
-    case eCSSUnit_Enumerated:
-      return FontWeight(aVal.GetIntValue());
-    case eCSSUnit_Normal:
-    case eCSSUnit_Null:
-      return FontWeight::Normal();
-    default:
-      MOZ_ASSERT_UNREACHABLE("Unknown font-weight descriptor value");
-      return FontWeight::Normal();
-  }
-}
-
 static WeightRange
-GetWeightRangeForDescriptor(const nsCSSValue& aVal,
+GetWeightRangeForDescriptor(const Maybe<StyleComputedFontWeightRange>& aVal,
                             gfxFontEntry::RangeFlags& aRangeFlags)
 {
-  if (aVal.GetUnit() == eCSSUnit_Null) {
+  if (!aVal) {
     aRangeFlags |= gfxFontEntry::RangeFlags::eAutoWeight;
     return WeightRange(FontWeight::Normal());
   }
-  if (aVal.GetUnit() == eCSSUnit_Pair) {
-    return WeightRange(GetWeightForDescriptor(aVal.GetPairValue().mXValue),
-                       GetWeightForDescriptor(aVal.GetPairValue().mYValue));
-  }
-  return WeightRange(GetWeightForDescriptor(aVal));
-}
-
-static FontSlantStyle
-GetStyleForDescriptor(const nsCSSValue& aVal)
-{
-  switch (aVal.GetUnit()) {
-    case eCSSUnit_Normal:
-    case eCSSUnit_Null:
-      return FontSlantStyle::Normal();
-    case eCSSUnit_Enumerated:
-      MOZ_ASSERT(aVal.GetIntValue() == NS_FONT_STYLE_ITALIC);
-      return FontSlantStyle::Italic();
-    case eCSSUnit_FontSlantStyle:
-      return aVal.GetFontSlantStyle();
-    default:
-      MOZ_ASSERT_UNREACHABLE("Unknown font-style descriptor value");
-      return FontSlantStyle::Normal();
-  }
+  return WeightRange(FontWeight(aVal->_0), FontWeight(aVal->_1));
 }
 
 static SlantStyleRange
-GetStyleRangeForDescriptor(const nsCSSValue& aVal,
+GetStyleRangeForDescriptor(const Maybe<StyleComputedFontStyleDescriptor>& aVal,
                            gfxFontEntry::RangeFlags& aRangeFlags)
 {
-  if (aVal.GetUnit() == eCSSUnit_Null) {
+  if (!aVal) {
     aRangeFlags |= gfxFontEntry::RangeFlags::eAutoSlantStyle;
     return SlantStyleRange(FontSlantStyle::Normal());
   }
-  if (aVal.GetUnit() == eCSSUnit_Pair) {
-    return SlantStyleRange(GetStyleForDescriptor(aVal.GetPairValue().mXValue),
-                           GetStyleForDescriptor(aVal.GetPairValue().mYValue));
-  }
-  return SlantStyleRange(GetStyleForDescriptor(aVal));
-}
-
-static FontStretch
-GetStretchForDescriptor(const nsCSSValue& aVal)
-{
-  switch (aVal.GetUnit()) {
-    case eCSSUnit_Null:
-      return FontStretch::Normal();
-    case eCSSUnit_FontStretch:
-      return aVal.GetFontStretch();
-    default:
-      MOZ_ASSERT_UNREACHABLE("Unknown font-style descriptor value");
-      return FontStretch::Normal();
+  auto& val = *aVal;
+  switch (val.tag) {
+    case StyleComputedFontStyleDescriptor::Tag::Normal:
+      return SlantStyleRange(FontSlantStyle::Normal());
+    case StyleComputedFontStyleDescriptor::Tag::Italic:
+      return SlantStyleRange(FontSlantStyle::Italic());
+    case StyleComputedFontStyleDescriptor::Tag::Oblique:
+      return SlantStyleRange(FontSlantStyle::Oblique(val.oblique._0),
+                             FontSlantStyle::Oblique(val.oblique._1));
   }
 }
 
 static StretchRange
-GetStretchRangeForDescriptor(const nsCSSValue& aVal,
+GetStretchRangeForDescriptor(const Maybe<StyleComputedFontStretchRange>& aVal,
                              gfxFontEntry::RangeFlags& aRangeFlags)
 {
-  if (aVal.GetUnit() == eCSSUnit_Null) {
+  if (!aVal) {
     aRangeFlags |= gfxFontEntry::RangeFlags::eAutoStretch;
     return StretchRange(FontStretch::Normal());
   }
-  if (aVal.GetUnit() == eCSSUnit_Pair) {
-    return StretchRange(GetStretchForDescriptor(aVal.GetPairValue().mXValue),
-                       GetStretchForDescriptor(aVal.GetPairValue().mYValue));
-  }
-  return StretchRange(GetStretchForDescriptor(aVal));
+  return StretchRange(FontStretch::FromStyle(aVal->_0),
+                      FontStretch::FromStyle(aVal->_1));
 }
 
+// TODO(emilio): Should this take an nsAtom* aFamilyName instead?
+//
+// All callers have one handy.
 /* static */ already_AddRefed<gfxUserFontEntry>
 FontFaceSet::FindOrCreateUserFontEntryFromFontFace(const nsACString& aFamilyName,
                                                    FontFace* aFontFace,
                                                    SheetType aSheetType)
 {
   FontFaceSet* set = aFontFace->GetPrimaryFontFaceSet();
 
-  nsCSSValue val;
-  nsCSSUnit unit;
-
   uint32_t languageOverride = NO_FONT_LANGUAGE_OVERRIDE;
-  uint8_t fontDisplay = NS_FONT_DISPLAY_AUTO;
+  StyleFontDisplay fontDisplay = StyleFontDisplay::Auto;
 
   gfxFontEntry::RangeFlags rangeFlags = gfxFontEntry::RangeFlags::eNoFlags;
 
   // set up weight
-  aFontFace->GetDesc(eCSSFontDesc_Weight, val);
-  WeightRange weight = GetWeightRangeForDescriptor(val, rangeFlags);
+  WeightRange weight =
+    GetWeightRangeForDescriptor(aFontFace->GetFontWeight(), rangeFlags);
 
   // set up stretch
-  aFontFace->GetDesc(eCSSFontDesc_Stretch, val);
-  StretchRange stretch = GetStretchRangeForDescriptor(val, rangeFlags);
+  StretchRange stretch =
+    GetStretchRangeForDescriptor(aFontFace->GetFontStretch(), rangeFlags);
 
   // set up font style
-  aFontFace->GetDesc(eCSSFontDesc_Style, val);
-  SlantStyleRange italicStyle = GetStyleRangeForDescriptor(val, rangeFlags);
+  SlantStyleRange italicStyle =
+    GetStyleRangeForDescriptor(aFontFace->GetFontStyle(), rangeFlags);
 
   // 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,
-                 "@font-face style has unexpected unit");
+  if (Maybe<StyleFontDisplay> display = aFontFace->GetFontDisplay()) {
+    fontDisplay = *display;
   }
 
   // set up font features
   nsTArray<gfxFontFeature> featureSettings;
-  aFontFace->GetDesc(eCSSFontDesc_FontFeatureSettings, val);
-  unit = val.GetUnit();
-  if (unit == eCSSUnit_Normal) {
-    // empty list of features
-  } else if (unit == eCSSUnit_PairList || unit == eCSSUnit_PairListDep) {
-    nsLayoutUtils::ComputeFontFeatures(val.GetPairListValue(), featureSettings);
-  } else {
-    NS_ASSERTION(unit == eCSSUnit_Null,
-                 "@font-face font-feature-settings has unexpected unit");
-  }
+  aFontFace->GetFontFeatureSettings(featureSettings);
 
   // set up font variations
   nsTArray<gfxFontVariation> variationSettings;
-  aFontFace->GetDesc(eCSSFontDesc_FontVariationSettings, val);
-  unit = val.GetUnit();
-  if (unit == eCSSUnit_Normal) {
-    // empty list of variations
-  } else if (unit == eCSSUnit_PairList || unit == eCSSUnit_PairListDep) {
-    nsLayoutUtils::ComputeFontVariations(val.GetPairListValue(), variationSettings);
-  } else {
-    NS_ASSERTION(unit == eCSSUnit_Null,
-                 "@font-face font-variation-settings has unexpected unit");
-  }
+  aFontFace->GetFontVariationSettings(variationSettings);
 
   // set up font language override
-  aFontFace->GetDesc(eCSSFontDesc_FontLanguageOverride, val);
-  unit = val.GetUnit();
-  if (unit == eCSSUnit_Normal) {
-    // empty feature string
-  } else if (unit == eCSSUnit_String) {
-    nsString stringValue;
-    val.GetStringValue(stringValue);
-    languageOverride = nsLayoutUtils::ParseFontLanguageOverride(stringValue);
-  } else {
-    NS_ASSERTION(unit == eCSSUnit_Null,
-                 "@font-face font-language-override has unexpected unit");
+  if (Maybe<StyleFontLanguageOverride> descriptor = aFontFace->GetFontLanguageOverride()) {
+    languageOverride = descriptor->_0;
   }
 
   // set up unicode-range
   gfxCharacterMap* unicodeRanges = aFontFace->GetUnicodeRangeAsCharacterMap();
 
   // set up src array
   nsTArray<gfxFontFaceSrc> srcArray;
 
@@ -1177,70 +1074,63 @@ FontFaceSet::FindOrCreateUserFontEntryFr
     gfxFontFaceSrc* face = srcArray.AppendElement();
     if (!face)
       return nullptr;
 
     face->mSourceType = gfxFontFaceSrc::eSourceType_Buffer;
     face->mBuffer = aFontFace->CreateBufferSource();
     face->mReferrerPolicy = mozilla::net::RP_Unset;
   } else {
-    aFontFace->GetDesc(eCSSFontDesc_Src, val);
-    unit = val.GetUnit();
-    if (unit == eCSSUnit_Array) {
-      // Hold a strong reference because content of val is going away
-      // in the loop below.
-      RefPtr<nsCSSValue::Array> srcArr = val.GetArrayValue();
-      size_t numSrc = srcArr->Count();
-
-      for (size_t i = 0; i < numSrc; i++) {
-        val = srcArr->Item(i);
-        unit = val.GetUnit();
-        gfxFontFaceSrc* face = srcArray.AppendElements(1);
-        if (!face)
-          return nullptr;
-
-        switch (unit) {
-
-        case eCSSUnit_Local_Font: {
-          nsAutoString localName;
-          val.GetStringValue(localName);
-          face->mLocalName.Append(NS_ConvertUTF16toUTF8(localName));
+    AutoTArray<StyleFontFaceSourceListComponent, 8> sourceListComponents;
+    aFontFace->GetSources(sourceListComponents);
+    size_t len = sourceListComponents.Length();
+    for (size_t i = 0; i < len; ++i) {
+      gfxFontFaceSrc* face = srcArray.AppendElement();
+      const auto& component = sourceListComponents[i];
+      switch (component.tag) {
+        case StyleFontFaceSourceListComponent::Tag::Local: {
+          nsAtom* atom = component.local._0;
+          face->mLocalName.Append(nsAtomCString(atom));
           face->mSourceType = gfxFontFaceSrc::eSourceType_Local;
           face->mURI = nullptr;
           face->mFormatFlags = 0;
           face->mReferrerPolicy = mozilla::net::RP_Unset;
           break;
         }
-        case eCSSUnit_URL: {
+        case StyleFontFaceSourceListComponent::Tag::Url: {
           face->mSourceType = gfxFontFaceSrc::eSourceType_URL;
-          nsIURI* uri = val.GetURLValue();
+          const URLValue* url = component.url._0;
+          nsIURI* uri = url->GetURI();
           face->mURI = uri ? new gfxFontSrcURI(uri) : nullptr;
-          URLValue* url = val.GetURLStructValue();
           face->mReferrer = url->mExtraData->GetReferrer();
           face->mReferrerPolicy = url->mExtraData->GetReferrerPolicy();
           face->mOriginPrincipal =
             new gfxFontSrcPrincipal(url->mExtraData->GetPrincipal());
           NS_ASSERTION(face->mOriginPrincipal, "null origin principal in @font-face rule");
 
           // agent and user stylesheets are treated slightly differently,
           // the same-site origin check and access control headers are
           // enforced against the sheet principal rather than the document
           // principal to allow user stylesheets to include @font-face rules
           face->mUseOriginPrincipal = (aSheetType == SheetType::User ||
                                        aSheetType == SheetType::Agent);
 
           face->mLocalName.Truncate();
           face->mFormatFlags = 0;
 
-          while (i + 1 < numSrc) {
-            val = srcArr->Item(i + 1);
-            if (val.GetUnit() != eCSSUnit_Font_Format)
+          while (i + 1 < len) {
+            const auto& maybeFontFormat = sourceListComponents[i + 1];
+            if (maybeFontFormat.tag != StyleFontFaceSourceListComponent::Tag::FormatHint) {
               break;
+            }
 
-            nsDependentString valueString(val.GetStringBufferValue());
+            nsDependentCSubstring valueString(
+                reinterpret_cast<const char*>(maybeFontFormat.format_hint.utf8_bytes),
+                maybeFontFormat.format_hint.length);
+
             if (valueString.LowerCaseEqualsASCII("woff")) {
               face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_WOFF;
             } else if (Preferences::GetBool(GFX_PREF_WOFF2_ENABLED) &&
                        valueString.LowerCaseEqualsASCII("woff2")) {
               face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_WOFF2;
             } else if (valueString.LowerCaseEqualsASCII("opentype")) {
               face->mFormatFlags |= gfxUserFontSet::FLAG_FORMAT_OPENTYPE;
             } else if (valueString.LowerCaseEqualsASCII("truetype")) {
@@ -1274,24 +1164,20 @@ FontFaceSet::FindOrCreateUserFontEntryFr
           if (!face->mURI) {
             // if URI not valid, omit from src array
             srcArray.RemoveLastElement();
             NS_WARNING("null url in @font-face rule");
             continue;
           }
           break;
         }
-        default:
-          NS_ASSERTION(unit == eCSSUnit_Local_Font || unit == eCSSUnit_URL,
-                       "strange unit type in font-face src array");
+        case StyleFontFaceSourceListComponent::Tag::FormatHint:
+          MOZ_ASSERT_UNREACHABLE("Should always come after a URL source, and be consumed already");
           break;
-        }
        }
-    } else {
-      NS_ASSERTION(unit == eCSSUnit_Null, "@font-face src has unexpected unit");
     }
   }
 
   if (srcArray.IsEmpty()) {
     return nullptr;
   }
 
   RefPtr<gfxUserFontEntry> entry =
@@ -2047,17 +1933,17 @@ FontFaceSet::UserFontSet::CreateUserFont
                                const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                                WeightRange aWeight,
                                StretchRange aStretch,
                                SlantStyleRange aStyle,
                                const nsTArray<gfxFontFeature>& aFeatureSettings,
                                const nsTArray<gfxFontVariation>& aVariationSettings,
                                uint32_t aLanguageOverride,
                                gfxCharacterMap* aUnicodeRanges,
-                               uint8_t aFontDisplay,
+                               StyleFontDisplay aFontDisplay,
                                RangeFlags aRangeFlags)
 {
   RefPtr<gfxUserFontEntry> entry =
     new FontFace::Entry(this, aFontFaceSrcList, aWeight, aStretch, aStyle,
                         aFeatureSettings, aVariationSettings,
                         aLanguageOverride, aUnicodeRanges,
                         aFontDisplay, aRangeFlags);
   return entry.forget();
--- a/layout/style/FontFaceSet.h
+++ b/layout/style/FontFaceSet.h
@@ -100,17 +100,17 @@ public:
                                    const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
                                    WeightRange aWeight,
                                    StretchRange aStretch,
                                    SlantStyleRange aStyle,
                                    const nsTArray<gfxFontFeature>& aFeatureSettings,
                                    const nsTArray<gfxFontVariation>& aVariationSettings,
                                    uint32_t aLanguageOverride,
                                    gfxCharacterMap* aUnicodeRanges,
-                                   uint8_t aFontDisplay,
+                                   StyleFontDisplay aFontDisplay,
                                    RangeFlags aRangeFlags) override;
 
   private:
     RefPtr<FontFaceSet> mFontFaceSet;
   };
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FontFaceSet, DOMEventTargetHelper)
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -371,19 +371,45 @@ SERVO_BINDING_FUNC(Servo_FontFaceRule_Ge
                    RawServoFontFaceRuleBorrowed rule,
                    uint32_t* line, uint32_t* column)
 SERVO_BINDING_FUNC(Servo_FontFaceRule_Length, uint32_t,
                    RawServoFontFaceRuleBorrowed rule)
 SERVO_BINDING_FUNC(Servo_FontFaceRule_IndexGetter, nsCSSFontDesc,
                    RawServoFontFaceRuleBorrowed rule, uint32_t index)
 SERVO_BINDING_FUNC(Servo_FontFaceRule_GetDeclCssText, void,
                    RawServoFontFaceRuleBorrowed rule, nsAString* result)
-SERVO_BINDING_FUNC(Servo_FontFaceRule_GetDescriptor, void,
+SERVO_BINDING_FUNC(Servo_FontFaceRule_GetFontWeight, bool,
+                   RawServoFontFaceRuleBorrowed rule,
+                   mozilla::StyleComputedFontWeightRange* out)
+SERVO_BINDING_FUNC(Servo_FontFaceRule_GetFontDisplay, bool,
+                   RawServoFontFaceRuleBorrowed rule,
+                   mozilla::StyleFontDisplay* out)
+SERVO_BINDING_FUNC(Servo_FontFaceRule_GetFontStyle, bool,
+                   RawServoFontFaceRuleBorrowed rule,
+                   mozilla::StyleComputedFontStyleDescriptor* out)
+SERVO_BINDING_FUNC(Servo_FontFaceRule_GetFontStretch, bool,
+                   RawServoFontFaceRuleBorrowed rule,
+                   mozilla::StyleComputedFontStretchRange* out)
+SERVO_BINDING_FUNC(Servo_FontFaceRule_GetFontLanguageOverride, bool,
                    RawServoFontFaceRuleBorrowed rule,
-                   nsCSSFontDesc desc, nsCSSValueBorrowedMut result)
+                   mozilla::StyleFontLanguageOverride* out)
+SERVO_BINDING_FUNC(Servo_FontFaceRule_GetFamilyName, nsAtom*,
+                   RawServoFontFaceRuleBorrowed rule)
+SERVO_BINDING_FUNC(Servo_FontFaceRule_GetUnicodeRanges, const mozilla::StyleUnicodeRange*,
+                   RawServoFontFaceRuleBorrowed rule,
+                   size_t* out_len)
+SERVO_BINDING_FUNC(Servo_FontFaceRule_GetSources, void,
+                   RawServoFontFaceRuleBorrowed rule,
+                   nsTArray<mozilla::StyleFontFaceSourceListComponent>* components)
+SERVO_BINDING_FUNC(Servo_FontFaceRule_GetVariationSettings, void,
+                   RawServoFontFaceRuleBorrowed rule,
+                   nsTArray<gfxFontVariation>* out)
+SERVO_BINDING_FUNC(Servo_FontFaceRule_GetFeatureSettings, void,
+                   RawServoFontFaceRuleBorrowed rule,
+                   nsTArray<gfxFontFeature>* out)
 SERVO_BINDING_FUNC(Servo_FontFaceRule_GetDescriptorCssText, void,
                    RawServoFontFaceRuleBorrowed rule,
                    nsCSSFontDesc desc, nsAString* result)
 SERVO_BINDING_FUNC(Servo_FontFaceRule_SetDescriptor, bool,
                    RawServoFontFaceRuleBorrowed rule,
                    nsCSSFontDesc desc, const nsACString* value,
                    RawGeckoURLExtraData* data)
 SERVO_BINDING_FUNC(Servo_FontFaceRule_ResetDescriptor, void,
@@ -876,19 +902,21 @@ SERVO_BINDING_FUNC(Servo_IntersectionObs
 SERVO_BINDING_FUNC(Servo_ParseTransformIntoMatrix, bool,
                    const nsAString* value,
                    bool* contains_3d_transform,
                    RawGeckoGfxMatrix4x4* result);
 SERVO_BINDING_FUNC(Servo_ParseFontShorthandForMatching, bool,
                    const nsAString* value,
                    RawGeckoURLExtraData* data,
                    RefPtr<SharedFontList>* family,
-                   nsCSSValueBorrowedMut style,
-                   nsCSSValueBorrowedMut stretch,
-                   nsCSSValueBorrowedMut weight);
+                   // We use ComputedFontStyleDescriptor just for convenience,
+                   // but the two values of Oblique are the same.
+                   mozilla::StyleComputedFontStyleDescriptor* style,
+                   float* stretch,
+                   float* weight);
 
 SERVO_BINDING_FUNC(Servo_ResolveLogicalProperty,
                    nsCSSPropertyID,
                    nsCSSPropertyID,
                    ComputedStyleBorrowed);
 SERVO_BINDING_FUNC(Servo_Property_LookupEnabledForAllContent,
                    nsCSSPropertyID,
                    const nsACString* name);
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -2361,39 +2361,16 @@ 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)
 {
   aFont->mLanguage = dont_AddRef(aAtom);
   aFont->mExplicitLanguage = true;
 }
 
 void
 Gecko_nsStyleFont_CopyLangFrom(nsStyleFont* aFont, const nsStyleFont* aSource)
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -577,19 +577,16 @@ 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);
 void Gecko_CSSValue_SetArray(nsCSSValueBorrowedMut css_value, int32_t len);
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -258,16 +258,25 @@ whitelist-types = [
     "mozilla::StyleShapeRadius",
     "mozilla::StyleGrid.*",
     "mozilla::UpdateAnimationsTasks",
     "mozilla::PointerCapabilities",
     "mozilla::LookAndFeel",
     "mozilla::gfx::Float",
     "mozilla::gfx::FontVariation",
     "mozilla::StyleImageLayerAttachment",
+    "mozilla::StyleComputedFontStretchRange",
+    "mozilla::StyleComputedFontStyleDescriptor",
+    "mozilla::StyleComputedFontWeightRange",
+    "mozilla::StyleFontDisplay",
+    "mozilla::StyleUnicodeRange",
+    "mozilla::StyleFontLanguageOverride",
+    "mozilla::StyleFontFaceSourceListComponent",
+    "gfxFontFeature",
+    "gfxFontVariation",
     ".*ThreadSafe.*Holder",
     "AnonymousContent",
     "AudioContext",
     "CapturingContentInfo",
     "DefaultDelete",
     "DOMIntersectionObserverEntry",
     "Element",
     "FontFamilyList",
@@ -484,16 +493,25 @@ structs-types = [
     "mozilla::FontStretch",
     "mozilla::FontSlantStyle",
     "mozilla::FontWeight",
     "mozilla::MallocSizeOf",
     "mozilla::OriginFlags",
     "mozilla::StyleMotion",
     "mozilla::UniquePtr",
     "mozilla::StyleDisplayMode",
+    "mozilla::StyleComputedFontStretchRange",
+    "mozilla::StyleComputedFontStyleDescriptor",
+    "mozilla::StyleComputedFontWeightRange",
+    "mozilla::StyleFontDisplay",
+    "mozilla::StyleUnicodeRange",
+    "mozilla::StyleFontLanguageOverride",
+    "mozilla::StyleFontFaceSourceListComponent",
+    "gfxFontFeature",
+    "gfxFontVariation",
     "ServoRawOffsetArc",
     "DeclarationBlockMutationClosure",
     "nsAttrValue",
     "nsIContent",
     "nsINode",
     "nsIDocument",
     "nsIDocument_DocumentTheme",
     "nsSimpleContentList",
--- a/layout/style/ServoCSSParser.cpp
+++ b/layout/style/ServoCSSParser.cpp
@@ -65,19 +65,19 @@ ServoCSSParser::ParseTransformIntoMatrix
                                         &aContains3DTransform,
                                         &aResult);
 }
 
 /* static */ bool
 ServoCSSParser::ParseFontShorthandForMatching(const nsAString& aValue,
                                               URLExtraData* aUrl,
                                               RefPtr<SharedFontList>& aList,
-                                              nsCSSValue& aStyle,
-                                              nsCSSValue& aStretch,
-                                              nsCSSValue& aWeight)
+                                              StyleComputedFontStyleDescriptor& aStyle,
+                                              float& aStretch,
+                                              float& aWeight)
 {
   return Servo_ParseFontShorthandForMatching(&aValue, aUrl, &aList,
                                              &aStyle, &aStretch, &aWeight);
 }
 
 /* static */ already_AddRefed<URLExtraData>
 ServoCSSParser::GetURLExtraData(nsIDocument* aDocument)
 {
--- a/layout/style/ServoCSSParser.h
+++ b/layout/style/ServoCSSParser.h
@@ -125,19 +125,19 @@ public:
    * @param aStyle The parsed FontStyle. (output)
    * @param aStretch The parsed FontStretch. (output)
    * @param aWeight The parsed FontWeight. (output)
    * @return Whether the value was successfully parsed.
    */
   static bool ParseFontShorthandForMatching(const nsAString& aValue,
                                             URLExtraData* aUrl,
                                             RefPtr<SharedFontList>& aList,
-                                            nsCSSValue& aStyle,
-                                            nsCSSValue& aStretch,
-                                            nsCSSValue& aWeight);
+                                            StyleComputedFontStyleDescriptor& aStyle,
+                                            float& aStretch,
+                                            float& aWeight);
 
   /**
    * Get a URLExtraData from |nsIDocument|.
    *
    * @param aDocument The current document.
    * @return The URLExtraData object.
    */
   static already_AddRefed<URLExtraData> GetURLExtraData(nsIDocument* aDocument);
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -97,34 +97,16 @@ 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)
 {
   if (mUnit <= eCSSUnit_DummyInherit) {
     // nothing to do, but put this important case first
   }
   else if (eCSSUnit_Percent <= mUnit) {
     mValue.mFloat = aCopy.mValue.mFloat;
@@ -170,25 +152,16 @@ 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 {
     MOZ_ASSERT(false, "unknown unit");
   }
 }
@@ -255,25 +228,16 @@ 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;
     }
   }
   return false;
@@ -440,37 +404,16 @@ void nsCSSValue::SetArrayValue(nsCSSValu
 void nsCSSValue::SetURLValue(mozilla::css::URLValue* aValue)
 {
   Reset();
   mUnit = eCSSUnit_URL;
   mValue.mURL = aValue;
   mValue.mURL->AddRef();
 }
 
-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)
 {
   // pairs should not be used for null/inherit/initial values
   MOZ_ASSERT(aValue &&
              aValue->mXValue.GetUnit() != eCSSUnit_Null &&
              aValue->mYValue.GetUnit() != eCSSUnit_Null &&
              aValue->mXValue.GetUnit() != eCSSUnit_Inherit &&
              aValue->mYValue.GetUnit() != eCSSUnit_Inherit &&
@@ -745,19 +688,16 @@ 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:
     case eCSSUnit_ViewportMin:
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -426,21 +426,16 @@ enum nsCSSUnit {
   eCSSUnit_Kilohertz    = 2001,    // (float) 1000 Hertz
 
   // Time units
   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;
@@ -465,19 +460,16 @@ 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;
   }
   template<typename T,
@@ -621,34 +613,16 @@ 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();
   inline const nsCSSValuePair& GetPairValue() const;
 
   inline nsCSSValueList* GetListValue();
   inline const nsCSSValueList* GetListValue() const;
 
   inline nsCSSValuePairList* GetPairListValue();
@@ -709,19 +683,16 @@ public:
   void SetStringValue(const nsString& aValue, nsCSSUnit aUnit);
   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 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 SetNoneValue();
 
   nsStyleCoord::CalcValue GetCalcValue() const;
   void SetCalcValue(const nsStyleCoord::CalcValue&);
 
@@ -762,19 +733,16 @@ 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) {
     return new (aItemCount) Array(aItemCount);
--- a/layout/style/nsFontFaceLoader.cpp
+++ b/layout/style/nsFontFaceLoader.cpp
@@ -75,19 +75,19 @@ nsFontFaceLoader::~nsFontFaceLoader()
     mFontFaceSet->RemoveLoader(this);
   }
 }
 
 void
 nsFontFaceLoader::StartedLoading(nsIStreamLoader* aStreamLoader)
 {
   int32_t loadTimeout;
-  uint8_t fontDisplay = GetFontDisplay();
-  if (fontDisplay == NS_FONT_DISPLAY_AUTO ||
-      fontDisplay == NS_FONT_DISPLAY_BLOCK) {
+  StyleFontDisplay fontDisplay = GetFontDisplay();
+  if (fontDisplay == StyleFontDisplay::Auto ||
+      fontDisplay == StyleFontDisplay::Block) {
     loadTimeout = GetFallbackDelay();
   } else {
     loadTimeout = GetShortFallbackDelay();
   }
 
   if (loadTimeout > 0) {
     NS_NewTimerWithFuncCallback(getter_AddRefs(mLoadTimer),
                                 LoadTimerCallback,
@@ -108,28 +108,28 @@ nsFontFaceLoader::LoadTimerCallback(nsIT
   nsFontFaceLoader* loader = static_cast<nsFontFaceLoader*>(aClosure);
 
   if (!loader->mFontFaceSet) {
     // We've been canceled
     return;
   }
 
   gfxUserFontEntry* ufe = loader->mUserFontEntry.get();
-  uint8_t fontDisplay = loader->GetFontDisplay();
+  StyleFontDisplay fontDisplay = loader->GetFontDisplay();
 
   // Depending upon the value of the font-display descriptor for the font,
   // their may be one or two timeouts associated with each font. The LOADING_SLOWLY
   // state indicates that the fallback font is shown. The LOADING_TIMED_OUT
   // state indicates that the fallback font is shown *and* the downloaded font
   // resource will not replace the fallback font when the load completes.
 
   bool updateUserFontSet = true;
   switch (fontDisplay) {
-    case NS_FONT_DISPLAY_AUTO:
-    case NS_FONT_DISPLAY_BLOCK:
+    case StyleFontDisplay::Auto:
+    case StyleFontDisplay::Block:
       // If the entry is loading, check whether it's >75% done; if so,
       // we allow another timeout period before showing a fallback font.
       if (ufe->mFontDataLoadingState == gfxUserFontEntry::LOADING_STARTED) {
         int64_t contentLength;
         uint32_t numBytesRead;
         if (NS_SUCCEEDED(loader->mChannel->GetContentLength(&contentLength)) &&
             contentLength > 0 &&
             contentLength < UINT32_MAX &&
@@ -151,29 +151,29 @@ nsFontFaceLoader::LoadTimerCallback(nsIT
           updateUserFontSet = false;
           LOG(("userfonts (%p) 75%% done, resetting timer\n", loader));
         }
       }
       if (updateUserFontSet) {
         ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_SLOWLY;
       }
       break;
-    case NS_FONT_DISPLAY_SWAP:
+    case StyleFontDisplay::Swap:
       ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_SLOWLY;
       break;
-    case NS_FONT_DISPLAY_FALLBACK: {
+    case StyleFontDisplay::Fallback: {
       if (ufe->mFontDataLoadingState == gfxUserFontEntry::LOADING_STARTED) {
         ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_SLOWLY;
       } else {
         ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_TIMED_OUT;
         updateUserFontSet = false;
       }
       break;
     }
-    case NS_FONT_DISPLAY_OPTIONAL:
+    case StyleFontDisplay::Optional:
       ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_TIMED_OUT;
       break;
 
     default:
       MOZ_ASSERT_UNREACHABLE("strange font-display value");
       break;
   }
 
@@ -184,17 +184,17 @@ nsFontFaceLoader::LoadTimerCallback(nsIT
     nsTArray<gfxUserFontSet*> fontSets;
     ufe->GetUserFontSets(fontSets);
     for (gfxUserFontSet* fontSet : fontSets) {
       nsPresContext* ctx = FontFaceSet::GetPresContextFor(fontSet);
       if (ctx) {
         fontSet->IncrementGeneration();
         ctx->UserFontSetUpdated(ufe);
         LOG(("userfonts (%p) timeout reflow for pres context %p display %d\n",
-             loader, ctx, fontDisplay));
+             loader, ctx, static_cast<int>(fontDisplay)));
       }
     }
   }
 }
 
 NS_IMPL_ISUPPORTS(nsFontFaceLoader,
                   nsIStreamLoaderObserver,
                   nsIRequestObserver)
@@ -216,17 +216,17 @@ nsFontFaceLoader::OnStreamComplete(nsISt
 
   mFontFaceSet->RemoveLoader(this);
 
   TimeStamp doneTime = TimeStamp::Now();
   TimeDuration downloadTime = doneTime - mStartTime;
   uint32_t downloadTimeMS = uint32_t(downloadTime.ToMilliseconds());
   Telemetry::Accumulate(Telemetry::WEBFONT_DOWNLOAD_TIME, downloadTimeMS);
 
-  if (GetFontDisplay() == NS_FONT_DISPLAY_FALLBACK) {
+  if (GetFontDisplay() == StyleFontDisplay::Fallback) {
     uint32_t loadTimeout = GetFallbackDelay();
     if (downloadTimeMS > loadTimeout &&
         (mUserFontEntry->mFontDataLoadingState ==
          gfxUserFontEntry::LOADING_SLOWLY)) {
       mUserFontEntry->mFontDataLoadingState =
         gfxUserFontEntry::LOADING_TIMED_OUT;
     }
   }
@@ -328,17 +328,16 @@ nsFontFaceLoader::Cancel()
   mFontFaceSet = nullptr;
   if (mLoadTimer) {
     mLoadTimer->Cancel();
     mLoadTimer = nullptr;
   }
   mChannel->Cancel(NS_BINDING_ABORTED);
 }
 
-uint8_t
+StyleFontDisplay
 nsFontFaceLoader::GetFontDisplay()
 {
-  uint8_t fontDisplay = NS_FONT_DISPLAY_AUTO;
-  if (StaticPrefs::layout_css_font_display_enabled()) {
-    fontDisplay = mUserFontEntry->GetFontDisplay();
+  if (!StaticPrefs::layout_css_font_display_enabled()) {
+    return StyleFontDisplay::Auto;
   }
-  return fontDisplay;
+  return mUserFontEntry->GetFontDisplay();
 }
--- a/layout/style/nsFontFaceLoader.h
+++ b/layout/style/nsFontFaceLoader.h
@@ -46,17 +46,17 @@ public:
   static void LoadTimerCallback(nsITimer* aTimer, void* aClosure);
 
   gfxUserFontEntry* GetUserFontEntry() const { return mUserFontEntry; }
 
 protected:
   virtual ~nsFontFaceLoader();
 
   // helper method for determining the font-display value
-  uint8_t GetFontDisplay();
+  mozilla::StyleFontDisplay GetFontDisplay();
 
 private:
   RefPtr<gfxUserFontEntry>  mUserFontEntry;
   nsCOMPtr<nsIURI>        mFontURI;
   RefPtr<mozilla::dom::FontFaceSet> mFontFaceSet;
   nsCOMPtr<nsIChannel>    mChannel;
   nsCOMPtr<nsITimer>      mLoadTimer;
   mozilla::TimeStamp      mStartTime;
--- a/layout/style/test/test_font_face_cascade.html
+++ b/layout/style/test/test_font_face_cascade.html
@@ -25,11 +25,11 @@ load_sheet(
   "@font-face { font-family: TestAuthor; src: url(about:invalid); }",
   "AUTHOR_SHEET");
 
 load_sheet(
   "@font-face { font-family: TestUser; src: url(about:invalid); }",
   "USER_SHEET");
 
 is([...document.fonts].map(f => f.family).join(" "),
-   '"TestAgent" "TestUser" "TestAuthor"',
+   'TestAgent TestUser TestAuthor',
    "@font-face rules are returned in correct cascade order");
 </script>
--- a/layout/style/test/test_font_loading_api.html
+++ b/layout/style/test/test_font_loading_api.html
@@ -994,17 +994,17 @@ function runTest() {
     style.textContent = ruleText;
 
     var rule = style.sheet.cssRules[0];
 
     var all = Array.from(document.fonts);
     is(all.length, 1, "document.fonts should contain one FontFace (TEST 33)");
 
     var face = all[0];
-    is(face.family, "\"something\"", "FontFace should have correct family value (TEST 33)");
+    is(face.family, "something", "FontFace should have correct family value (TEST 33)");
     Object.keys(nonDefaultValues).forEach(function(aDesc) {
       var ok_todo = aDesc == "variant" ? todo : ok;
       ok_todo(face[aDesc] == nonDefaultValues[aDesc][1], "FontFace should have correct " + aDesc + " value (TEST 33)");
     });
 
     is(document.fonts.status, "loaded", "document.fonts.status should still be loaded (TEST 33)");
     is(face.status, "unloaded", "FontFace.status should be unloaded (TEST 33)");
 
--- a/servo/components/style/cbindgen.toml
+++ b/servo/components/style/cbindgen.toml
@@ -1,33 +1,54 @@
 header = """/* 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/. */"""
 autogen_warning = """/* DO NOT MODIFY THIS MANUALLY! This file was generated using cbindgen.
  * To generate this file:
  *   1. Get the latest cbindgen using `cargo install --force cbindgen`
  *      a. Alternatively, you can clone `https://github.com/eqrion/cbindgen` and use a tagged release
  *   2. Run `rustup run nightly cbindgen toolkit/library/rust/ --lockfile Cargo.lock --crate style -o layout/style/ServoStyleConsts.h`
- */"""
+ */
+class nsAtom;
+namespace mozilla {
+  namespace css {
+    struct URLValue;
+  }
+  // Work-around weird cbindgen renaming.
+  typedef css::URLValue StyleURLValue;
+  typedef nsAtom StylensAtom;
+}
+"""
 include_guard = "mozilla_ServoStyleConsts_h"
 include_version = true
 braces = "SameLine"
 line_length = 80
 tab_width = 2
 language = "C++"
 namespaces = ["mozilla"]
 
+[parse]
+parse_deps = true
+include = ["cssparser"]
+
 [struct]
 derive_eq = true
 
 [enum]
 derive_helper_methods = true
 
 [export]
 prefix = "Style"
 include = [
   "StyleAppearance",
+  "StyleComputedFontStretchRange",
+  "StyleComputedFontStyleDescriptor",
+  "StyleComputedFontWeightRange",
   "StyleDisplay",
   "StyleDisplayMode",
   "StyleFillRule",
-  "StylePathCommand"
+  "StyleFontDisplay",
+  "StyleFontFaceSourceListComponent",
+  "StyleFontLanguageOverride",
+  "StylePathCommand",
+  "StyleUnicodeRange",
 ]
 item_types = ["enums", "structs", "typedefs"]
--- a/servo/components/style/font_face.rs
+++ b/servo/components/style/font_face.rs
@@ -19,17 +19,17 @@ use shared_lock::{SharedRwLockReadGuard,
 use std::fmt::{self, Write};
 use str::CssStringWriter;
 use style_traits::{Comma, CssWriter, OneOrMoreSeparated, ParseError};
 use style_traits::{StyleParseErrorKind, ToCss};
 use style_traits::values::SequenceWriter;
 use values::computed::font::FamilyName;
 use values::generics::font::FontStyle as GenericFontStyle;
 use values::specified::Angle;
-use values::specified::font::{AbsoluteFontWeight, FontStretch as SpecifiedFontStretch};
+use values::specified::font::{AbsoluteFontWeight, FontStretch};
 #[cfg(feature = "gecko")]
 use values::specified::font::{SpecifiedFontFeatureSettings, SpecifiedFontVariationSettings};
 use values::specified::font::SpecifiedFontStyle;
 use values::specified::url::SpecifiedUrl;
 
 /// A source for a font-face rule.
 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
 #[derive(Clone, Debug, Eq, PartialEq, ToCss)]
@@ -40,16 +40,29 @@ pub enum Source {
     #[css(function)]
     Local(FamilyName),
 }
 
 impl OneOrMoreSeparated for Source {
     type S = Comma;
 }
 
+/// A POD representation for Gecko. All pointers here are non-owned and as such
+/// can't outlive the rule they came from, but we can't enforce that via C++.
+///
+/// All the strings are of course utf8.
+#[cfg(feature = "gecko")]
+#[repr(u8)]
+#[allow(missing_docs)]
+pub enum FontFaceSourceListComponent {
+    Url(*const ::gecko_bindings::structs::mozilla::css::URLValue),
+    Local(*mut ::gecko_bindings::structs::nsAtom),
+    FormatHint { length: usize, utf8_bytes: *const u8 },
+}
+
 /// A `UrlSource` represents a font-face source that has been specified with a
 /// `url()` function.
 ///
 /// <https://drafts.csswg.org/css-fonts/#src-desc>
 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct UrlSource {
     /// The specified url.
@@ -79,73 +92,126 @@ impl ToCss for UrlSource {
 }
 
 /// A font-display value for a @font-face rule.
 /// The font-display descriptor determines how a font face is displayed based
 /// on whether and when it is downloaded and ready to use.
 #[allow(missing_docs)]
 #[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
 #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, Parse, PartialEq, ToComputedValue, ToCss)]
+#[repr(u8)]
 pub enum FontDisplay {
     Auto,
     Block,
     Swap,
     Fallback,
     Optional,
 }
 
+macro_rules! impl_range {
+    ($range:ident, $component:ident) => {
+        impl Parse for $range {
+            fn parse<'i, 't>(
+                context: &ParserContext,
+                input: &mut Parser<'i, 't>,
+            ) -> Result<Self, ParseError<'i>> {
+                let first = $component::parse(context, input)?;
+                let second = input
+                    .try(|input| $component::parse(context, input))
+                    .unwrap_or_else(|_| first.clone());
+                Ok($range(first, second))
+            }
+        }
+        impl ToCss for $range {
+            fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
+            where
+                W: fmt::Write,
+            {
+                self.0.to_css(dest)?;
+                if self.0 != self.1 {
+                    dest.write_str(" ")?;
+                    self.1.to_css(dest)?;
+                }
+                Ok(())
+            }
+        }
+    }
+}
+
 /// The font-weight descriptor:
 ///
 /// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-weight
-#[derive(Clone, Debug, PartialEq, ToCss)]
-pub struct FontWeight(pub AbsoluteFontWeight, pub Option<AbsoluteFontWeight>);
+#[derive(Clone, Debug, PartialEq)]
+pub struct FontWeightRange(pub AbsoluteFontWeight, pub AbsoluteFontWeight);
+impl_range!(FontWeightRange, AbsoluteFontWeight);
 
-impl Parse for FontWeight {
-    fn parse<'i, 't>(
-        context: &ParserContext,
-        input: &mut Parser<'i, 't>,
-    ) -> Result<Self, ParseError<'i>> {
-        let first = AbsoluteFontWeight::parse(context, input)?;
-        let second = input
-            .try(|input| AbsoluteFontWeight::parse(context, input))
-            .ok();
-        Ok(FontWeight(first, second))
+/// The computed representation of the above so Gecko can read them easily.
+///
+/// This one is needed because cbindgen doesn't know how to generate
+/// specified::Number.
+#[repr(C)]
+#[allow(missing_docs)]
+pub struct ComputedFontWeightRange(f32, f32);
+
+impl FontWeightRange {
+    /// Returns a computed font-stretch range.
+    pub fn compute(&self) -> ComputedFontWeightRange {
+        ComputedFontWeightRange(self.0.compute().0, self.1.compute().0)
     }
 }
 
 /// The font-stretch descriptor:
 ///
 /// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-stretch
-#[derive(Clone, Debug, PartialEq, ToCss)]
-pub struct FontStretch(pub SpecifiedFontStretch, pub Option<SpecifiedFontStretch>);
+#[derive(Clone, Debug, PartialEq,)]
+pub struct FontStretchRange(pub FontStretch, pub FontStretch);
+impl_range!(FontStretchRange, FontStretch);
+
+/// The computed representation of the above, so that
+/// Gecko can read them easily.
+#[repr(C)]
+#[allow(missing_docs)]
+pub struct ComputedFontStretchRange(f32, f32);
 
-impl Parse for FontStretch {
-    fn parse<'i, 't>(
-        context: &ParserContext,
-        input: &mut Parser<'i, 't>,
-    ) -> Result<Self, ParseError<'i>> {
-        let first = SpecifiedFontStretch::parse(context, input)?;
-        let second = input
-            .try(|input| SpecifiedFontStretch::parse(context, input))
-            .ok();
-        Ok(FontStretch(first, second))
+impl FontStretchRange {
+    /// Returns a computed font-stretch range.
+    pub fn compute(&self) -> ComputedFontStretchRange {
+        fn compute_stretch(s: &FontStretch) -> f32 {
+            match *s {
+                FontStretch::Keyword(ref kw) => kw.compute().0,
+                FontStretch::Stretch(ref p) => p.get(),
+                FontStretch::System(..) => unreachable!(),
+            }
+        }
+
+        ComputedFontStretchRange(compute_stretch(&self.0), compute_stretch(&self.1))
     }
 }
 
 /// The font-style descriptor:
 ///
 /// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-style
 #[derive(Clone, Debug, PartialEq)]
 #[allow(missing_docs)]
 pub enum FontStyle {
     Normal,
     Italic,
     Oblique(Angle, Angle),
 }
 
+/// The computed representation of the above, with angles in degrees, so that
+/// Gecko can read them easily.
+#[repr(u8)]
+#[allow(missing_docs)]
+pub enum ComputedFontStyleDescriptor {
+    Normal,
+    Italic,
+    Oblique(f32, f32),
+}
+
 impl Parse for FontStyle {
     fn parse<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
     ) -> Result<Self, ParseError<'i>> {
         let style = SpecifiedFontStyle::parse(context, input)?;
         Ok(match style {
             GenericFontStyle::Normal => FontStyle::Normal,
@@ -180,16 +246,32 @@ impl ToCss for FontStyle {
                     second.to_css(dest)?;
                 }
                 Ok(())
             },
         }
     }
 }
 
+impl FontStyle {
+    /// Returns a computed font-style descriptor.
+    pub fn compute(&self) -> ComputedFontStyleDescriptor {
+        match *self {
+            FontStyle::Normal => ComputedFontStyleDescriptor::Normal,
+            FontStyle::Italic => ComputedFontStyleDescriptor::Italic,
+            FontStyle::Oblique(ref first, ref second) => {
+                ComputedFontStyleDescriptor::Oblique(
+                    SpecifiedFontStyle::compute_angle_degrees(first),
+                    SpecifiedFontStyle::compute_angle_degrees(second),
+                )
+            }
+        }
+    }
+}
+
 /// Parse the block inside a `@font-face` rule.
 ///
 /// Note that the prelude parsing code lives in the `stylesheets` module.
 pub fn parse_font_face_block(
     context: &ParserContext,
     input: &mut Parser,
     location: SourceLocation,
 ) -> FontFaceRuleData {
@@ -454,20 +536,20 @@ font_face_descriptors! {
         /// The alternative sources for this font face.
         "src" sources / mSrc: Vec<Source>,
     ]
     optional descriptors = [
         /// The style of this font face.
         "font-style" style / mStyle: FontStyle,
 
         /// The weight of this font face.
-        "font-weight" weight / mWeight: FontWeight,
+        "font-weight" weight / mWeight: FontWeightRange,
 
         /// The stretch of this font face.
-        "font-stretch" stretch / mStretch: FontStretch,
+        "font-stretch" stretch / mStretch: FontStretchRange,
 
         /// The display of this font face.
         "font-display" display / mDisplay: FontDisplay,
 
         /// The ranges of code points outside of which this font face should not be used.
         "unicode-range" unicode_range / mUnicodeRange: Vec<UnicodeRange>,
 
         /// The feature settings of this font face.
--- a/servo/components/style/gecko/rules.rs
+++ b/servo/components/style/gecko/rules.rs
@@ -1,147 +1,18 @@
 /* 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/. */
 
 //! Bindings for CSS Rule objects
 
-use byteorder::{BigEndian, WriteBytesExt};
 use counter_style::{self, CounterBound};
-use cssparser::UnicodeRange;
-use font_face::{FontDisplay, FontWeight, FontStretch, FontStyle, Source};
+use font_face::Source;
 use gecko_bindings::structs::{self, nsCSSValue};
 use gecko_bindings::sugar::ns_css_value::ToNsCssValue;
-use properties::longhands::font_language_override;
-use std::str;
-use values::computed::font::FamilyName;
-use values::generics::font::FontTag;
-use values::specified::font::{AbsoluteFontWeight, FontStretch as SpecifiedFontStretch};
-use values::specified::font::{SpecifiedFontFeatureSettings, SpecifiedFontVariationSettings};
-use values::specified::font::SpecifiedFontStyle;
-
-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) {
-        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)
-    }
-}
-
-impl ToNsCssValue for FontTag {
-    fn convert(self, nscssvalue: &mut nsCSSValue) {
-        let mut raw = [0u8; 4];
-        (&mut raw[..]).write_u32::<BigEndian>(self.0).unwrap();
-        nscssvalue.set_string(str::from_utf8(&raw).unwrap());
-    }
-}
-
-impl<'a> ToNsCssValue for &'a SpecifiedFontFeatureSettings {
-    fn convert(self, nscssvalue: &mut nsCSSValue) {
-        if self.0.is_empty() {
-            nscssvalue.set_normal();
-            return;
-        }
-
-        nscssvalue.set_pair_list(self.0.iter().map(|entry| {
-            let mut index = nsCSSValue::null();
-            index.set_integer(entry.value.value());
-            (entry.tag.into(), index)
-        }))
-    }
-}
-
-impl<'a> ToNsCssValue for &'a SpecifiedFontVariationSettings {
-    fn convert(self, nscssvalue: &mut nsCSSValue) {
-        if self.0.is_empty() {
-            nscssvalue.set_normal();
-            return;
-        }
-
-        nscssvalue.set_pair_list(self.0.iter().map(|entry| {
-            let mut value = nsCSSValue::null();
-            value.set_number(entry.value.into());
-            (entry.tag.into(), value)
-        }))
-    }
-}
-
-macro_rules! descriptor_range_conversion {
-    ($name:ident) => {
-        impl<'a> ToNsCssValue for &'a $name {
-            fn convert(self, nscssvalue: &mut nsCSSValue) {
-                let $name(ref first, ref second) = *self;
-                let second = match *second {
-                    None => {
-                        nscssvalue.set_from(first);
-                        return;
-                    },
-                    Some(ref second) => second,
-                };
-
-                let mut a = nsCSSValue::null();
-                let mut b = nsCSSValue::null();
-
-                a.set_from(first);
-                b.set_from(second);
-
-                nscssvalue.set_pair(&a, &b);
-            }
-        }
-    };
-}
-
-descriptor_range_conversion!(FontWeight);
-descriptor_range_conversion!(FontStretch);
-
-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_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 {
-    fn convert(self, nscssvalue: &mut nsCSSValue) {
-        match *self {
-            font_language_override::SpecifiedValue::Normal => nscssvalue.set_normal(),
-            font_language_override::SpecifiedValue::Override(ref lang) => {
-                nscssvalue.set_string(&*lang)
-            },
-            // This path is unreachable because the descriptor is only specified by the user.
-            font_language_override::SpecifiedValue::System(_) => unreachable!(),
-        }
-    }
-}
 
 impl<'a> ToNsCssValue for &'a Vec<Source> {
     fn convert(self, nscssvalue: &mut nsCSSValue) {
         let src_len = self.iter().fold(0, |acc, src| {
             acc + match *src {
                 // Each format hint takes one position in the array of mSrc.
                 Source::Url(ref url) => url.format_hints.len() + 1,
                 Source::Local(_) => 1,
@@ -170,41 +41,16 @@ impl<'a> ToNsCssValue for &'a Vec<Source
                     next!().set_local_font(&family.name);
                 },
             }
         }
         debug_assert!(target_srcs.next().is_none(), "Should have filled all slots");
     }
 }
 
-impl<'a> ToNsCssValue for &'a Vec<UnicodeRange> {
-    fn convert(self, nscssvalue: &mut nsCSSValue) {
-        let target_ranges = nscssvalue
-            .set_array((self.len() * 2) as i32)
-            .as_mut_slice()
-            .chunks_mut(2);
-        for (range, target) in self.iter().zip(target_ranges) {
-            target[0].set_integer(range.start as i32);
-            target[1].set_integer(range.end as i32);
-        }
-    }
-}
-
-impl<'a> ToNsCssValue for &'a FontDisplay {
-    fn convert(self, nscssvalue: &mut nsCSSValue) {
-        nscssvalue.set_enum(match *self {
-            FontDisplay::Auto => structs::NS_FONT_DISPLAY_AUTO,
-            FontDisplay::Block => structs::NS_FONT_DISPLAY_BLOCK,
-            FontDisplay::Swap => structs::NS_FONT_DISPLAY_SWAP,
-            FontDisplay::Fallback => structs::NS_FONT_DISPLAY_FALLBACK,
-            FontDisplay::Optional => structs::NS_FONT_DISPLAY_OPTIONAL,
-        } as i32)
-    }
-}
-
 impl<'a> ToNsCssValue for &'a counter_style::System {
     fn convert(self, nscssvalue: &mut nsCSSValue) {
         use counter_style::System::*;
         match *self {
             Cyclic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_CYCLIC as i32),
             Numeric => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_NUMERIC as i32),
             Alphabetic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_ALPHABETIC as i32),
             Symbolic => nscssvalue.set_enum(structs::NS_STYLE_COUNTER_SYSTEM_SYMBOLIC as i32),
--- a/servo/components/style/gecko_bindings/sugar/ns_css_value.rs
+++ b/servo/components/style/gecko_bindings/sugar/ns_css_value.rs
@@ -172,31 +172,16 @@ impl nsCSSValue {
         self.set_string_internal(s, nsCSSUnit::eCSSUnit_Font_Format);
     }
 
     /// 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) }
     }
 
     /// Set to an integer value
     pub fn set_integer(&mut self, value: i32) {
         self.set_int_internal(value, nsCSSUnit::eCSSUnit_Integer)
     }
--- a/servo/components/style/values/computed/font.rs
+++ b/servo/components/style/values/computed/font.rs
@@ -742,16 +742,17 @@ pub type FontFeatureSettings = FontSetti
 /// The computed value for font-variation-settings.
 pub type FontVariationSettings = FontSettings<VariationValue<Number>>;
 
 /// font-language-override can only have a single three-letter
 /// OpenType "language system" tag, so we should be able to compute
 /// it and store it as a 32-bit integer
 /// (see http://www.microsoft.com/typography/otspec/languagetags.htm).
 #[derive(Clone, Copy, Debug, Eq, MallocSizeOf, PartialEq)]
+#[repr(C)]
 pub struct FontLanguageOverride(pub u32);
 
 impl FontLanguageOverride {
     #[inline]
     /// Get computed default value of `font-language-override` with 0
     pub fn zero() -> FontLanguageOverride {
         FontLanguageOverride(0)
     }
--- a/servo/components/style/values/computed/percentage.rs
+++ b/servo/components/style/values/computed/percentage.rs
@@ -22,16 +22,17 @@ use values::generics::NonNegative;
     MallocSizeOf,
     PartialEq,
     PartialOrd,
     SpecifiedValueInfo,
     ToAnimatedValue,
     ToAnimatedZero,
     ToComputedValue,
 )]
+#[repr(C)]
 pub struct Percentage(pub CSSFloat);
 
 impl Percentage {
     /// 0%
     #[inline]
     pub fn zero() -> Self {
         Percentage(0.)
     }
--- a/servo/components/style/values/specified/font.rs
+++ b/servo/components/style/values/specified/font.rs
@@ -287,24 +287,26 @@ pub const DEFAULT_FONT_STYLE_OBLIQUE_ANG
 ///
 /// The maximum angle value that `font-style: oblique` should compute to.
 pub const FONT_STYLE_OBLIQUE_MAX_ANGLE_DEGREES: f32 = 90.;
 
 /// The minimum angle value that `font-style: oblique` should compute to.
 pub const FONT_STYLE_OBLIQUE_MIN_ANGLE_DEGREES: f32 = -90.;
 
 impl SpecifiedFontStyle {
-    /// Gets a clamped angle from a specified Angle.
-    pub fn compute_angle(angle: &Angle) -> ComputedAngle {
-        ComputedAngle::Deg(
-            angle
-                .degrees()
-                .max(FONT_STYLE_OBLIQUE_MIN_ANGLE_DEGREES)
-                .min(FONT_STYLE_OBLIQUE_MAX_ANGLE_DEGREES),
-        )
+    /// Gets a clamped angle in degrees from a specified Angle.
+    pub fn compute_angle_degrees(angle: &Angle) -> f32 {
+        angle
+            .degrees()
+            .max(FONT_STYLE_OBLIQUE_MIN_ANGLE_DEGREES)
+            .min(FONT_STYLE_OBLIQUE_MAX_ANGLE_DEGREES)
+    }
+
+    fn compute_angle(angle: &Angle) -> ComputedAngle {
+        ComputedAngle::Deg(Self::compute_angle_degrees(angle))
     }
 
     /// Parse a suitable angle for font-style: oblique.
     pub fn parse_angle<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
     ) -> Result<Angle, ParseError<'i>> {
         let angle = Angle::parse(context, input)?;
@@ -375,16 +377,17 @@ impl Parse for FontStyle {
     }
 }
 
 /// A value for the `font-stretch` property.
 ///
 /// https://drafts.csswg.org/css-fonts-4/#font-stretch-prop
 #[allow(missing_docs)]
 #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss)]
+#[repr(u8)]
 pub enum FontStretch {
     Stretch(Percentage),
     Keyword(FontStretchKeyword),
     #[css(skip)]
     System(SystemFont),
 }
 
 /// A keyword value for `font-stretch`.
@@ -2052,38 +2055,50 @@ pub enum FontLanguageOverride {
 
 impl FontLanguageOverride {
     #[inline]
     /// Get default value with `normal`
     pub fn normal() -> FontLanguageOverride {
         FontLanguageOverride::Normal
     }
 
+    /// The ToComputedValue implementation for non-system-font
+    /// FontLanguageOverride, used for @font-face descriptors.
+    #[inline]
+    pub fn compute_non_system(&self) -> computed::FontLanguageOverride {
+        match *self {
+            FontLanguageOverride::Normal => computed::FontLanguageOverride(0),
+            FontLanguageOverride::Override(ref lang) => {
+                if lang.is_empty() || lang.len() > 4 {
+                    return computed::FontLanguageOverride(0);
+                }
+                let mut bytes = [b' '; 4];
+                for (byte, lang_byte) in bytes.iter_mut().zip(lang.as_bytes()) {
+                    if !lang_byte.is_ascii() {
+                        return computed::FontLanguageOverride(0);
+                    }
+                    *byte = *lang_byte;
+                }
+                computed::FontLanguageOverride(BigEndian::read_u32(&bytes))
+            },
+            FontLanguageOverride::System(..) => unreachable!(),
+        }
+    }
+
     system_font_methods!(FontLanguageOverride, font_language_override);
 }
 
 impl ToComputedValue for FontLanguageOverride {
     type ComputedValue = computed::FontLanguageOverride;
 
     #[inline]
     fn to_computed_value(&self, context: &Context) -> computed::FontLanguageOverride {
         match *self {
-            FontLanguageOverride::Normal => computed::FontLanguageOverride(0),
-            FontLanguageOverride::Override(ref lang) => {
-                if lang.is_empty() || lang.len() > 4 || !lang.is_ascii() {
-                    return computed::FontLanguageOverride(0);
-                }
-                let mut computed_lang = lang.to_string();
-                while computed_lang.len() < 4 {
-                    computed_lang.push(' ');
-                }
-                let bytes = computed_lang.into_bytes();
-                computed::FontLanguageOverride(BigEndian::read_u32(&bytes))
-            },
             FontLanguageOverride::System(_) => self.compute_system(context),
+            _ => self.compute_non_system(),
         }
     }
     #[inline]
     fn from_computed_value(computed: &computed::FontLanguageOverride) -> Self {
         if computed.0 == 0 {
             return FontLanguageOverride::Normal;
         }
         let mut buf = [0; 4];
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -2476,49 +2476,171 @@ pub unsafe extern "C" fn Servo_FontFaceR
     rule: RawServoFontFaceRuleBorrowed,
     result: *mut nsAString,
 ) {
     read_locked_arc(rule, |rule: &FontFaceRule| {
         rule.decl_to_css(result.as_mut().unwrap()).unwrap();
     })
 }
 
-#[no_mangle]
-pub unsafe extern "C" fn Servo_FontFaceRule_GetDescriptor(
+
+macro_rules! simple_font_descriptor_getter {
+    ($function_name:ident, $gecko_type:ident, $field:ident, $compute:ident) => {
+        #[no_mangle]
+        pub unsafe extern "C" fn $function_name(
+            rule: RawServoFontFaceRuleBorrowed,
+            out: *mut structs::$gecko_type,
+        ) -> bool {
+            read_locked_arc(rule, |rule: &FontFaceRule| {
+                match rule.$field {
+                    None => return false,
+                    Some(ref f) => {
+                        // FIXME(emilio): We should probably teach bindgen about
+                        // cbindgen.toml and making it hide the types and use
+                        // the rust ones instead. This would make transmute()
+                        // calls unnecessary.
+                        // unsafe: cbindgen guarantees the same representation.
+                        *out = ::std::mem::transmute(f.$compute());
+                    }
+                }
+                true
+            })
+        }
+    }
+}
+
+simple_font_descriptor_getter!(Servo_FontFaceRule_GetFontWeight, StyleComputedFontWeightRange, weight, compute);
+simple_font_descriptor_getter!(Servo_FontFaceRule_GetFontStretch, StyleComputedFontStretchRange, stretch, compute);
+simple_font_descriptor_getter!(Servo_FontFaceRule_GetFontStyle, StyleComputedFontStyleDescriptor, style, compute);
+simple_font_descriptor_getter!(Servo_FontFaceRule_GetFontDisplay, StyleFontDisplay, display, clone);
+simple_font_descriptor_getter!(Servo_FontFaceRule_GetFontLanguageOverride, StyleFontLanguageOverride, language_override, compute_non_system);
+
+#[no_mangle]
+pub unsafe extern "C" fn Servo_FontFaceRule_GetFamilyName(
     rule: RawServoFontFaceRuleBorrowed,
-    desc: nsCSSFontDesc,
-    result: nsCSSValueBorrowedMut,
-) {
+) -> *mut nsAtom {
+    read_locked_arc(rule, |rule: &FontFaceRule| {
+        // TODO(emilio): font-family is a mandatory descriptor, can't we unwrap
+        // here, and remove the null-checks in Gecko?
+        rule.family.as_ref().map_or(ptr::null_mut(), |f| f.name.as_ptr())
+    })
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn Servo_FontFaceRule_GetUnicodeRanges(
+    rule: RawServoFontFaceRuleBorrowed,
+    out_len: *mut usize,
+) -> *const structs::StyleUnicodeRange {
+    *out_len = 0;
     read_locked_arc(rule, |rule: &FontFaceRule| {
-        macro_rules! to_css_value {
-            (
-                valid: [$($v_enum_name:ident => $field:ident,)*]
-                invalid: [$($i_enum_name:ident,)*]
-            ) => {
-                match desc {
-                    $(
-                        nsCSSFontDesc::$v_enum_name => {
-                            if let Some(ref value) = rule.$field {
-                                result.set_from(value);
-                            }
+        let ranges = match rule.unicode_range {
+            Some(ref ranges) => ranges,
+            None => return ptr::null(),
+        };
+        *out_len = ranges.len();
+        ranges.as_ptr() as *const _
+    })
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn Servo_FontFaceRule_GetSources(
+    rule: RawServoFontFaceRuleBorrowed,
+    out: *mut nsTArray<structs::StyleFontFaceSourceListComponent>,
+) {
+    use style::font_face::{Source, FontFaceSourceListComponent};
+    let out = &mut *out;
+    read_locked_arc(rule, |rule: &FontFaceRule| {
+        let sources = match rule.sources {
+            Some(ref s) => s,
+            None => return,
+        };
+        let len = sources.iter().fold(0, |acc, src| {
+            acc + match *src {
+                // Each format hint takes one position in the array of mSrc.
+                Source::Url(ref url) => url.format_hints.len() + 1,
+                Source::Local(_) => 1,
+            }
+        });
+
+        out.set_len(len as u32);
+
+        let mut iter = out.iter_mut();
+
+        {
+            let mut set_next = |component: FontFaceSourceListComponent| {
+                // transmute: cbindgen ensures they have the same representation.
+                *iter.next().expect("miscalculated length") =
+                    ::std::mem::transmute(component);
+            };
+
+            for source in sources.iter() {
+                match *source {
+                    Source::Url(ref url) => {
+                        set_next(FontFaceSourceListComponent::Url(url.url.url_value.get()));
+                        for hint in url.format_hints.iter() {
+                            set_next(FontFaceSourceListComponent::FormatHint {
+                                length: hint.len(),
+                                utf8_bytes: hint.as_ptr(),
+                            });
                         }
-                    )*
-                    $(
-                        nsCSSFontDesc::$i_enum_name => {
-                            debug_assert!(false, "not a valid font descriptor");
-                        }
-                    )*
+                    }
+                    Source::Local(ref name) => {
+                        set_next(FontFaceSourceListComponent::Local(name.name.as_ptr()));
+                    }
                 }
             }
         }
-        apply_font_desc_list!(to_css_value)
+
+        assert!(iter.next().is_none(), "miscalculated");
     })
 }
 
 #[no_mangle]
+pub unsafe extern "C" fn Servo_FontFaceRule_GetVariationSettings(
+    rule: RawServoFontFaceRuleBorrowed,
+    variations: *mut nsTArray<structs::gfxFontVariation>,
+) {
+    read_locked_arc(rule, |rule: &FontFaceRule| {
+        let source_variations = match rule.variation_settings {
+            Some(ref v) => v,
+            None => return,
+        };
+
+        (*variations).set_len(source_variations.0.len() as u32);
+        for (target, source) in (*variations).iter_mut().zip(source_variations.0.iter()) {
+            *target = structs::gfxFontVariation {
+                mTag: source.tag.0,
+                mValue: source.value.get(),
+            };
+        }
+    });
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn Servo_FontFaceRule_GetFeatureSettings(
+    rule: RawServoFontFaceRuleBorrowed,
+    features: *mut nsTArray<structs::gfxFontFeature>,
+) {
+    read_locked_arc(rule, |rule: &FontFaceRule| {
+        let source_features = match rule.feature_settings {
+            Some(ref v) => v,
+            None => return,
+        };
+
+        (*features).set_len(source_features.0.len() as u32);
+        for (target, source) in (*features).iter_mut().zip(source_features.0.iter()) {
+            *target = structs::gfxFontFeature {
+                mTag: source.tag.0,
+                mValue: source.value.value() as u32,
+            };
+        }
+    });
+}
+
+#[no_mangle]
 pub unsafe extern "C" fn Servo_FontFaceRule_GetDescriptorCssText(
     rule: RawServoFontFaceRuleBorrowed,
     desc: nsCSSFontDesc,
     result: *mut nsAString,
 ) {
     read_locked_arc(rule, |rule: &FontFaceRule| {
         let mut writer = CssWriter::new(result.as_mut().unwrap());
         macro_rules! to_css_text {
@@ -5634,79 +5756,83 @@ pub extern "C" fn Servo_ParseTransformIn
     let result = unsafe { result.as_mut() }.expect("not a valid matrix");
     let contain_3d = unsafe { contain_3d.as_mut() }.expect("not a valid bool");
     *result = m.to_row_major_array();
     *contain_3d = is_3d;
     true
 }
 
 #[no_mangle]
-pub extern "C" fn Servo_ParseFontShorthandForMatching(
+pub unsafe extern "C" fn Servo_ParseFontShorthandForMatching(
     value: *const nsAString,
     data: *mut URLExtraData,
     family: *mut structs::RefPtr<structs::SharedFontList>,
-    style: nsCSSValueBorrowedMut,
-    stretch: nsCSSValueBorrowedMut,
-    weight: nsCSSValueBorrowedMut
+    style: *mut structs::StyleComputedFontStyleDescriptor,
+    stretch: *mut f32,
+    weight: *mut f32,
 ) -> bool {
+    use style::font_face::ComputedFontStyleDescriptor;
     use style::properties::shorthands::font;
     use style::values::generics::font::FontStyle as GenericFontStyle;
-    use style::values::specified::font::{FontFamily, FontWeight, FontStyle, SpecifiedFontStyle};
-
-    let string = unsafe { (*value).to_string() };
+    use style::values::computed::font::FontWeight as ComputedFontWeight;
+    use style::values::specified::font::{FontFamily, FontWeight, FontStretch, FontStyle, SpecifiedFontStyle};
+
+    let string = (*value).to_string();
     let mut input = ParserInput::new(&string);
     let mut parser = Parser::new(&mut input);
-    let url_data = unsafe { UrlExtraData::from_ptr_ref(&data) };
+    let url_data = UrlExtraData::from_ptr_ref(&data);
     let context = ParserContext::new(
         Origin::Author,
         url_data,
         Some(CssRuleType::FontFace),
         ParsingMode::DEFAULT,
         QuirksMode::NoQuirks,
         None,
         None,
     );
 
     let font = match parser.parse_entirely(|f| font::parse_value(&context, f)) {
         Ok(f) => f,
         Err(..) => return false,
     };
 
     // The system font is not acceptable, so we return false.
-    let family = unsafe { &mut *family };
+    let family = &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),
+    *style = ::std::mem::transmute(match *specified_font_style {
+        GenericFontStyle::Normal => ComputedFontStyleDescriptor::Normal,
+        GenericFontStyle::Italic => ComputedFontStyleDescriptor::Italic,
         GenericFontStyle::Oblique(ref angle) => {
-            style.set_font_style(SpecifiedFontStyle::compute_angle(angle).degrees())
+            let angle = SpecifiedFontStyle::compute_angle_degrees(angle);
+            ComputedFontStyleDescriptor::Oblique(angle, angle)
         }
-    }
-
-    if font.font_stretch.get_system().is_some() {
-        return false;
-    }
-    stretch.set_from(&font.font_stretch);
-
-    match font.font_weight {
-        FontWeight::Absolute(w) => weight.set_font_weight(w.compute().0),
+    });
+
+    *stretch = match font.font_stretch {
+        FontStretch::Keyword(ref k) => k.compute().0,
+        FontStretch::Stretch(ref p) => p.get(),
+        FontStretch::System(_) => return false,
+    };
+
+    *weight = match font.font_weight {
+        FontWeight::Absolute(w) => w.compute().0,
         // Resolve relative font weights against the initial of font-weight
         // (normal, which is equivalent to 400).
-        FontWeight::Bolder => weight.set_enum(structs::NS_FONT_WEIGHT_BOLD as i32),
-        FontWeight::Lighter => weight.set_enum(structs::NS_FONT_WEIGHT_THIN as i32),
+        FontWeight::Bolder => ComputedFontWeight::normal().bolder().0,
+        FontWeight::Lighter => ComputedFontWeight::normal().lighter().0,
         FontWeight::System(_) => return false,
-    }
+    };
 
     true
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn Servo_SourceSizeList_Parse(
     value: *const nsACString,
 ) -> *mut RawServoSourceSizeList {