Backed out 5 changesets (bug 1496486) for build bustages on gfxUserFontSet.h. CLOSED TREE
authorBrindusan Cristian <cbrindusan@mozilla.com>
Tue, 09 Oct 2018 16:58:38 +0300
changeset 495991 be1729663405c3f81c34ef5008cda8893d32e04e
parent 495990 09728d62f4d0af80f8add2db38e9eebde096f98b
child 495992 bbd428acbe9e14511be7d6afae4bd381806ef7b8
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)
bugs1496486
milestone64.0a1
backs out6b740afea4037c8d83d8ff3329a0c72689f13867
5cf44e254ac30b84fa82e302e21d29e0602c59b8
8e465202c355f19b05fb741ef0be74afab6a6842
86382b2249f6eab5f660e6e6c3aea69909e7f956
ab92ed3e0a2369a5a1764ba8e496e8f186fdbcd1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Backed out 5 changesets (bug 1496486) for build bustages on gfxUserFontSet.h. CLOSED TREE Backed out changeset 6b740afea403 (bug 1496486) Backed out changeset 5cf44e254ac3 (bug 1496486) Backed out changeset 8e465202c355 (bug 1496486) Backed out changeset 86382b2249f6 (bug 1496486) Backed out changeset ab92ed3e0a23 (bug 1496486)
build/moz.configure/rust.configure
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
taskcluster/scripts/misc/build-cbindgen.sh
--- a/build/moz.configure/rust.configure
+++ b/build/moz.configure/rust.configure
@@ -289,17 +289,17 @@ cbindgen = check_prog('CBINDGEN', add_ru
                       when=depends(build_project)
                       (lambda build_project: build_project != 'js'))
 
 
 @depends_if(cbindgen)
 @checking('cbindgen version')
 @imports(_from='textwrap', _import='dedent')
 def cbindgen_version(cbindgen):
-    cbindgen_min_version = Version('0.6.4')
+    cbindgen_min_version = Version('0.6.2')
 
     # cbindgen x.y.z
     version = Version(check_cmd_output(cbindgen, '--version').strip().split(" ")[1])
 
     if version < cbindgen_min_version:
         die(dedent('''\
         cbindgen version {} is too old. At least version {} is required.
 
--- a/gfx/src/FontPropertyTypes.h
+++ b/gfx/src/FontPropertyTypes.h
@@ -270,26 +270,16 @@ 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,16 +36,22 @@
 
 #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,
-             StyleFontDisplay aFontDisplay,
+             uint8_t 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,
-                          StyleFontDisplay aFontDisplay,
+                          uint8_t 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,
-                               StyleFontDisplay aFontDisplay,
+                               uint8_t 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,
-                               StyleFontDisplay aFontDisplay,
+                               uint8_t 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(),
-             static_cast<int>(aUserFontEntry->GetFontDisplay())));
+             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,
-                              mozilla::StyleFontDisplay aFontDisplay,
+                              uint8_t 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,
-                               mozilla::StyleFontDisplay aFontDisplay,
+                               uint8_t 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,
-                                   mozilla::StyleFontDisplay aFontDisplay,
+                                   uint8_t 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,
-                     mozilla::StyleFontDisplay aFontDisplay,
+                     uint8_t 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,
-                 mozilla::StyleFontDisplay aFontDisplay,
+                 uint8_t 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();
     }
 
-    mozilla::StyleFontDisplay GetFontDisplay() const { return mFontDisplay; }
+    uint8_t 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;
-    mozilla::StyleFontDisplay mFontDisplay; // timing of userfont fallback
+    bool                     mUnsupportedFormat;
+    uint8_t                  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,16 +10120,110 @@ 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,17 +218,33 @@ FontFace::InitializeSource(const StringO
   SetStatus(FontFaceLoadStatus::Loading);
   DoLoad();
 }
 
 void
 FontFace::GetFamily(nsString& aResult)
 {
   mFontFaceSet->FlushUserFontSet();
-  GetDesc(eCSSFontDesc_Family, aResult);
+
+  // 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);
+  }
 }
 
 void
 FontFace::SetFamily(const nsAString& aValue, ErrorResult& aRv)
 {
   mFontFaceSet->FlushUserFontSet();
   SetDescriptor(eCSSFontDesc_Family, aValue, aRv);
 }
@@ -274,16 +290,20 @@ 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);
@@ -582,16 +602,23 @@ 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) {
@@ -634,101 +661,29 @@ FontFace::SetUserFontEntry(gfxUserFontEn
     FontFaceLoadStatus newStatus =
       LoadStateToStatus(mUserFontEntry->LoadState());
     if (newStatus > mStatus) {
       SetStatus(newStatus);
     }
   }
 }
 
-Maybe<StyleComputedFontWeightRange>
-FontFace::GetFontWeight() const
-{
-  StyleComputedFontWeightRange range;
-  if (!Servo_FontFaceRule_GetFontWeight(GetData(), &range)) {
-    return Nothing();
-  }
-  return Some(range);
-}
-
-Maybe<StyleComputedFontStretchRange>
-FontFace::GetFontStretch() const
-{
-  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);
-}
-
-Maybe<StyleFontLanguageOverride>
-FontFace::GetFontLanguageOverride() const
+bool
+FontFace::GetFamilyName(nsCString& aResult)
 {
-  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;
-}
+  nsCSSValue value;
+  GetDesc(eCSSFontDesc_Family, value);
 
-void
-FontFace::GetFontFeatureSettings(nsTArray<gfxFontFeature>& aFeatures) const
-{
-  Servo_FontFaceRule_GetFeatureSettings(GetData(), &aFeatures);
-}
+  if (value.GetUnit() == eCSSUnit_String) {
+    nsString familyname;
+    value.GetStringValue(familyname);
+    AppendUTF16toUTF8(familyname, aResult);
+  }
 
-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());
+  return !aResult.IsEmpty();
 }
 
 void
 FontFace::DisconnectFromRule()
 {
   MOZ_ASSERT(HasRule());
 
   // Make a copy of the descriptors.
@@ -835,25 +790,29 @@ FontFace::EnsurePromise()
 
 gfxCharacterMap*
 FontFace::GetUnicodeRangeAsCharacterMap()
 {
   if (!mUnicodeRangeDirty) {
     return mUnicodeRange;
   }
 
-  size_t len;
-  const StyleUnicodeRange* rangesPtr =
-    Servo_FontFaceRule_GetUnicodeRanges(GetData(), &len);
+  nsCSSValue val;
+  GetDesc(eCSSFontDesc_UnicodeRange, val);
 
-  Span<const StyleUnicodeRange> ranges(rangesPtr, len);
-  if (!ranges.IsEmpty()) {
+  if (val.GetUnit() == eCSSUnit_Array) {
     mUnicodeRange = new gfxCharacterMap();
-    for (auto& range : ranges) {
-      mUnicodeRange->SetRange(range.start, range.end);
+    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);
     }
   } else {
     mUnicodeRange = nullptr;
   }
 
   mUnicodeRangeDirty = false;
   return mUnicodeRange;
 }
--- a/layout/style/FontFace.h
+++ b/layout/style/FontFace.h
@@ -4,19 +4,16 @@
  * 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;
@@ -53,17 +50,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,
-          StyleFontDisplay aFontDisplay,
+          uint8_t aFontDisplay,
           RangeFlags aRangeFlags)
       : gfxUserFontEntry(aFontSet, aFontFaceSrcList, aWeight, aStretch,
                          aStyle, aFeatureSettings, aVariationSettings,
                          aLanguageOverride,
                          aUnicodeRanges, aFontDisplay,
                          aRangeFlags) {}
 
     virtual void SetLoadState(UserFontLoadState aLoadState) override;
@@ -85,25 +82,17 @@ 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; }
 
-  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;
+  void GetDesc(nsCSSFontDesc aDescID, nsCSSValue& aResult) const;
 
   gfxUserFontEntry* CreateUserFontEntry();
   gfxUserFontEntry* GetUserFontEntry() const { return mUserFontEntry; }
   void SetUserFontEntry(gfxUserFontEntry* aEntry);
 
   /**
    * Returns whether this object is in the specified FontFaceSet.
    */
@@ -112,19 +101,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 null if a valid family name was not available.
+   * '"Times"').  Returns whether a valid family name was available.
    */
-  nsAtom* GetFamilyName() const;
+  bool GetFamilyName(nsCString& aResult);
 
   /**
    * 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,46 +206,53 @@ void
 FontFaceSet::ParseFontShorthandForMatching(
                             const nsAString& aFont,
                             RefPtr<SharedFontList>& aFamilyList,
                             FontWeight& aWeight,
                             FontStretch& aStretch,
                             FontSlantStyle& aStyle,
                             ErrorResult& aRv)
 {
-  StyleComputedFontStyleDescriptor style;
-  float stretch;
-  float weight;
+  nsCSSValue style;
+  nsCSSValue stretch;
+  nsCSSValue weight;
 
   // FIXME(emilio): This Servo -> nsCSSValue -> Gecko conversion is stupid,
   // Servo understands the font types.
   RefPtr<URLExtraData> url = ServoCSSParser::GetURLExtraData(mDocument);
   if (!ServoCSSParser::ParseFontShorthandForMatching(
         aFont, url, aFamilyList, style, stretch, weight)) {
     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
     return;
   }
 
-  switch (style.tag) {
-    case StyleComputedFontStyleDescriptor::Tag::Normal:
+  switch (style.GetUnit()) {
+    case eCSSUnit_Normal:
       aStyle = FontSlantStyle::Normal();
       break;
-    case StyleComputedFontStyleDescriptor::Tag::Italic:
+    case eCSSUnit_Enumerated:
+      MOZ_ASSERT(style.GetIntValue() == NS_FONT_STYLE_ITALIC);
       aStyle = FontSlantStyle::Italic();
       break;
-    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);
+    case eCSSUnit_FontSlantStyle:
+      aStyle = style.GetFontSlantStyle();
       break;
+    default:
+      MOZ_ASSERT_UNREACHABLE("Unknown unit for font-style");
   }
 
-  aWeight = FontWeight(weight);
-  aStretch = FontStretch::FromStyle(stretch);
+  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();
 }
 
 static bool
 HasAnyCharacterInUnicodeRange(gfxUserFontEntry* aEntry,
                               const nsAString& aInput)
 {
   const char16_t* p = aInput.Data();
   const char16_t* end = p + aInput.Length();
@@ -821,94 +828,107 @@ 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)
 {
-  nsAtom* fontFamily = aFontFace->GetFamilyName();
-  if (!fontFamily) {
+  nsAutoCString fontfamily;
+  if (!aFontFace->GetFamilyName(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(family, aFontFace, SheetType::Doc);
+      FindOrCreateUserFontEntryFromFontFace(fontfamily, aFontFace,
+                                            SheetType::Doc);
     if (!entry) {
       return;
     }
     aFontFace->SetUserFontEntry(entry);
   }
 
   aFontSetModified = true;
-  mUserFontSet->AddUserFontEntry(family, aFontFace->GetUserFontEntry());
+  mUserFontSet->AddUserFontEntry(fontfamily, aFontFace->GetUserFontEntry());
 }
 
 void
 FontFaceSet::InsertRuleFontFace(FontFace* aFontFace, SheetType aSheetType,
                                 nsTArray<FontFaceRecord>& aOldRecords,
                                 bool& aFontSetModified)
 {
-  nsAtom* fontFamily = aFontFace->GetFamilyName();
-  if (!fontFamily) {
+  nsAutoCString fontfamily;
+  if (!aFontFace->GetFamilyName(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) {
-        if (aFontFace->HasLocalSrc()) {
+      if (mUserFontSet->mLocalRulesUsed &&
+          mUserFontSet->mRebuildLocalRules) {
+        nsCSSValue val;
+        aFontFace->GetDesc(eCSSFontDesc_Src, val);
+        nsCSSUnit unit = val.GetUnit();
+        if (unit == eCSSUnit_Array && HasLocalSrc(val.GetArrayValue())) {
           // 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(family, entry);
+      mUserFontSet->AddUserFontEntry(fontfamily, 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
@@ -916,17 +936,17 @@ FontFaceSet::InsertRuleFontFace(FontFace
         aFontSetModified = true;
       }
       return;
     }
   }
 
   // this is a new rule:
   RefPtr<gfxUserFontEntry> entry =
-    FindOrCreateUserFontEntryFromFontFace(family, aFontFace, aSheetType);
+    FindOrCreateUserFontEntryFromFontFace(fontfamily, 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
@@ -954,119 +974,202 @@ 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(family, entry);
+  mUserFontSet->AddUserFontEntry(fontfamily, entry);
 }
 
 /* static */ already_AddRefed<gfxUserFontEntry>
 FontFaceSet::FindOrCreateUserFontEntryFromFontFace(FontFace* aFontFace)
 {
-  nsAtom* fontFamily = aFontFace->GetFamilyName();
-  if (!fontFamily) {
+  nsAutoCString fontfamily;
+  if (!aFontFace->GetFamilyName(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(nsAtomCString(fontFamily), aFontFace,
+  return FindOrCreateUserFontEntryFromFontFace(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 Maybe<StyleComputedFontWeightRange>& aVal,
+GetWeightRangeForDescriptor(const nsCSSValue& aVal,
                             gfxFontEntry::RangeFlags& aRangeFlags)
 {
-  if (!aVal) {
+  if (aVal.GetUnit() == eCSSUnit_Null) {
     aRangeFlags |= gfxFontEntry::RangeFlags::eAutoWeight;
     return WeightRange(FontWeight::Normal());
   }
-  return WeightRange(FontWeight(aVal->_0), FontWeight(aVal->_1));
+  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();
+  }
 }
 
 static SlantStyleRange
-GetStyleRangeForDescriptor(const Maybe<StyleComputedFontStyleDescriptor>& aVal,
+GetStyleRangeForDescriptor(const nsCSSValue& aVal,
                            gfxFontEntry::RangeFlags& aRangeFlags)
 {
-  if (!aVal) {
+  if (aVal.GetUnit() == eCSSUnit_Null) {
     aRangeFlags |= gfxFontEntry::RangeFlags::eAutoSlantStyle;
     return SlantStyleRange(FontSlantStyle::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));
+  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();
   }
 }
 
 static StretchRange
-GetStretchRangeForDescriptor(const Maybe<StyleComputedFontStretchRange>& aVal,
+GetStretchRangeForDescriptor(const nsCSSValue& aVal,
                              gfxFontEntry::RangeFlags& aRangeFlags)
 {
-  if (!aVal) {
+  if (aVal.GetUnit() == eCSSUnit_Null) {
     aRangeFlags |= gfxFontEntry::RangeFlags::eAutoStretch;
     return StretchRange(FontStretch::Normal());
   }
-  return StretchRange(FontStretch::FromStyle(aVal->_0),
-                      FontStretch::FromStyle(aVal->_1));
+  if (aVal.GetUnit() == eCSSUnit_Pair) {
+    return StretchRange(GetStretchForDescriptor(aVal.GetPairValue().mXValue),
+                       GetStretchForDescriptor(aVal.GetPairValue().mYValue));
+  }
+  return StretchRange(GetStretchForDescriptor(aVal));
 }
 
-// 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;
-  StyleFontDisplay fontDisplay = StyleFontDisplay::Auto;
+  uint8_t fontDisplay = NS_FONT_DISPLAY_AUTO;
 
   gfxFontEntry::RangeFlags rangeFlags = gfxFontEntry::RangeFlags::eNoFlags;
 
   // set up weight
-  WeightRange weight =
-    GetWeightRangeForDescriptor(aFontFace->GetFontWeight(), rangeFlags);
+  aFontFace->GetDesc(eCSSFontDesc_Weight, val);
+  WeightRange weight = GetWeightRangeForDescriptor(val, rangeFlags);
 
   // set up stretch
-  StretchRange stretch =
-    GetStretchRangeForDescriptor(aFontFace->GetFontStretch(), rangeFlags);
+  aFontFace->GetDesc(eCSSFontDesc_Stretch, val);
+  StretchRange stretch = GetStretchRangeForDescriptor(val, rangeFlags);
 
   // set up font style
-  SlantStyleRange italicStyle =
-    GetStyleRangeForDescriptor(aFontFace->GetFontStyle(), rangeFlags);
+  aFontFace->GetDesc(eCSSFontDesc_Style, val);
+  SlantStyleRange italicStyle = GetStyleRangeForDescriptor(val, rangeFlags);
 
   // set up font display
-  if (Maybe<StyleFontDisplay> display = aFontFace->GetFontDisplay()) {
-    fontDisplay = *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");
   }
 
   // set up font features
   nsTArray<gfxFontFeature> featureSettings;
-  aFontFace->GetFontFeatureSettings(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");
+  }
 
   // set up font variations
   nsTArray<gfxFontVariation> variationSettings;
-  aFontFace->GetFontVariationSettings(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");
+  }
 
   // set up font language override
-  if (Maybe<StyleFontLanguageOverride> descriptor = aFontFace->GetFontLanguageOverride()) {
-    languageOverride = descriptor->_0;
+  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");
   }
 
   // set up unicode-range
   gfxCharacterMap* unicodeRanges = aFontFace->GetUnicodeRangeAsCharacterMap();
 
   // set up src array
   nsTArray<gfxFontFaceSrc> srcArray;
 
@@ -1074,63 +1177,70 @@ 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 {
-    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));
+    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));
           face->mSourceType = gfxFontFaceSrc::eSourceType_Local;
           face->mURI = nullptr;
           face->mFormatFlags = 0;
           face->mReferrerPolicy = mozilla::net::RP_Unset;
           break;
         }
-        case StyleFontFaceSourceListComponent::Tag::Url: {
+        case eCSSUnit_URL: {
           face->mSourceType = gfxFontFaceSrc::eSourceType_URL;
-          const URLValue* url = component.url._0;
-          nsIURI* uri = url->GetURI();
+          nsIURI* uri = val.GetURLValue();
           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 < len) {
-            const auto& maybeFontFormat = sourceListComponents[i + 1];
-            if (maybeFontFormat.tag != StyleFontFaceSourceListComponent::Tag::FormatHint) {
+          while (i + 1 < numSrc) {
+            val = srcArr->Item(i + 1);
+            if (val.GetUnit() != eCSSUnit_Font_Format)
               break;
-            }
 
-            nsDependentCSubstring valueString(
-                reinterpret_cast<const char*>(maybeFontFormat.format_hint.utf8_bytes),
-                maybeFontFormat.format_hint.length);
-
+            nsDependentString valueString(val.GetStringBufferValue());
             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")) {
@@ -1164,20 +1274,24 @@ 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;
         }
-        case StyleFontFaceSourceListComponent::Tag::FormatHint:
-          MOZ_ASSERT_UNREACHABLE("Should always come after a URL source, and be consumed already");
+        default:
+          NS_ASSERTION(unit == eCSSUnit_Local_Font || unit == eCSSUnit_URL,
+                       "strange unit type in font-face src array");
           break;
+        }
        }
+    } else {
+      NS_ASSERTION(unit == eCSSUnit_Null, "@font-face src has unexpected unit");
     }
   }
 
   if (srcArray.IsEmpty()) {
     return nullptr;
   }
 
   RefPtr<gfxUserFontEntry> entry =
@@ -1933,17 +2047,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,
-                               StyleFontDisplay aFontDisplay,
+                               uint8_t 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,
-                                   StyleFontDisplay aFontDisplay,
+                                   uint8_t 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,45 +371,19 @@ 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_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,
+SERVO_BINDING_FUNC(Servo_FontFaceRule_GetDescriptor, void,
                    RawServoFontFaceRuleBorrowed rule,
-                   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)
+                   nsCSSFontDesc desc, nsCSSValueBorrowedMut result)
 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,
@@ -902,21 +876,19 @@ 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,
-                   // We use ComputedFontStyleDescriptor just for convenience,
-                   // but the two values of Oblique are the same.
-                   mozilla::StyleComputedFontStyleDescriptor* style,
-                   float* stretch,
-                   float* weight);
+                   nsCSSValueBorrowedMut style,
+                   nsCSSValueBorrowedMut stretch,
+                   nsCSSValueBorrowedMut 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
@@ -2224,17 +2224,17 @@ Gecko_CSSValue_SetPixelLength(nsCSSValue
   MOZ_ASSERT(aCSSValue->GetUnit() == eCSSUnit_Null ||
              aCSSValue->GetUnit() == eCSSUnit_Pixel);
   aCSSValue->SetFloatValue(aLen, eCSSUnit_Pixel);
 }
 
 void
 Gecko_CSSValue_SetCalc(nsCSSValueBorrowedMut aCSSValue, nsStyleCoord::CalcValue aCalc)
 {
-  aCSSValue->SetCalcValue(aCalc);
+  aCSSValue->SetCalcValue(&aCalc);
 }
 
 nsStyleCoord::CalcValue
 Gecko_CSSValue_GetCalc(nsCSSValueBorrowed aCSSValue)
 {
   return aCSSValue->GetCalcValue();
 }
 
@@ -2276,16 +2276,23 @@ Gecko_CSSValue_SetArray(nsCSSValueBorrow
 {
   MOZ_ASSERT(aCSSValue->GetUnit() == eCSSUnit_Null);
   RefPtr<nsCSSValue::Array> array
     = nsCSSValue::Array::Create(aLength);
   aCSSValue->SetArrayValue(array, eCSSUnit_Array);
 }
 
 void
+Gecko_CSSValue_SetURL(nsCSSValueBorrowedMut aCSSValue, URLValue* aURL)
+{
+  MOZ_ASSERT(aCSSValue->GetUnit() == eCSSUnit_Null);
+  aCSSValue->SetURLValue(aURL);
+}
+
+void
 Gecko_CSSValue_SetInt(nsCSSValueBorrowedMut aCSSValue,
                       int32_t aInteger, nsCSSUnit aUnit)
 {
   aCSSValue->SetIntValue(aInteger, aUnit);
 }
 
 void
 Gecko_CSSValue_SetFloat(nsCSSValueBorrowedMut aCSSValue,
@@ -2354,16 +2361,39 @@ 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,24 +577,28 @@ 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);
+void Gecko_CSSValue_SetURL(nsCSSValueBorrowedMut css_value, mozilla::css::URLValue* uri);
 void Gecko_CSSValue_SetInt(nsCSSValueBorrowedMut css_value, int32_t integer, nsCSSUnit unit);
 void Gecko_CSSValue_SetFloat(nsCSSValueBorrowedMut css_value, float value, nsCSSUnit unit);
 void Gecko_CSSValue_SetPair(nsCSSValueBorrowedMut css_value,
                             nsCSSValueBorrowed xvalue, nsCSSValueBorrowed yvalue);
 void Gecko_CSSValue_SetList(nsCSSValueBorrowedMut css_value, uint32_t len);
 void Gecko_CSSValue_SetPairList(nsCSSValueBorrowedMut css_value, uint32_t len);
 void Gecko_CSSValue_InitSharedList(nsCSSValueBorrowedMut css_value, uint32_t len);
 void Gecko_CSSValue_Drop(nsCSSValueBorrowedMut css_value);
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -258,25 +258,16 @@ 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",
@@ -493,25 +484,16 @@ 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,
-                                              StyleComputedFontStyleDescriptor& aStyle,
-                                              float& aStretch,
-                                              float& aWeight)
+                                              nsCSSValue& aStyle,
+                                              nsCSSValue& aStretch,
+                                              nsCSSValue& 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,
-                                            StyleComputedFontStyleDescriptor& aStyle,
-                                            float& aStretch,
-                                            float& aWeight);
+                                            nsCSSValue& aStyle,
+                                            nsCSSValue& aStretch,
+                                            nsCSSValue& 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
@@ -76,23 +76,55 @@ nsCSSValue::nsCSSValue(const nsString& a
 nsCSSValue::nsCSSValue(nsCSSValue::Array* aValue, nsCSSUnit aUnit)
   : mUnit(aUnit)
 {
   MOZ_ASSERT(UnitHasArrayValue(), "bad unit");
   mValue.mArray = aValue;
   mValue.mArray->AddRef();
 }
 
+nsCSSValue::nsCSSValue(mozilla::css::URLValue* aValue)
+  : mUnit(eCSSUnit_URL)
+{
+  mValue.mURL = aValue;
+  mValue.mURL->AddRef();
+}
+
+nsCSSValue::nsCSSValue(mozilla::css::GridTemplateAreasValue* aValue)
+  : mUnit(eCSSUnit_GridTemplateAreas)
+{
+  mValue.mGridTemplateAreas = aValue;
+  mValue.mGridTemplateAreas->AddRef();
+}
+
 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;
@@ -104,16 +136,20 @@ nsCSSValue::nsCSSValue(const nsCSSValue&
   }
   else if (eCSSUnit_Integer <= mUnit && mUnit <= eCSSUnit_Enumerated) {
     mValue.mInt = aCopy.mValue.mInt;
   }
   else if (UnitHasArrayValue()) {
     mValue.mArray = aCopy.mValue.mArray;
     mValue.mArray->AddRef();
   }
+  else if (eCSSUnit_URL == mUnit) {
+    mValue.mURL = aCopy.mValue.mURL;
+    mValue.mURL->AddRef();
+  }
   else if (eCSSUnit_Pair == mUnit) {
     mValue.mPair = aCopy.mValue.mPair;
     mValue.mPair->AddRef();
   }
   else if (eCSSUnit_List == mUnit) {
     mValue.mList = aCopy.mValue.mList;
     mValue.mList->AddRef();
   }
@@ -126,20 +162,33 @@ nsCSSValue::nsCSSValue(const nsCSSValue&
   }
   else if (eCSSUnit_PairList == mUnit) {
     mValue.mPairList = aCopy.mValue.mPairList;
     mValue.mPairList->AddRef();
   }
   else if (eCSSUnit_PairListDep == mUnit) {
     mValue.mPairListDependent = aCopy.mValue.mPairListDependent;
   }
+  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");
   }
 }
@@ -183,33 +232,48 @@ bool nsCSSValue::operator==(const nsCSSV
                         GetBufferValue(aOther.mValue.mString)) == 0);
     }
     else if ((eCSSUnit_Integer <= mUnit) && (mUnit <= eCSSUnit_Enumerated)) {
       return mValue.mInt == aOther.mValue.mInt;
     }
     else if (UnitHasArrayValue()) {
       return *mValue.mArray == *aOther.mValue.mArray;
     }
+    else if (eCSSUnit_URL == mUnit) {
+      return mValue.mURL->Equals(*aOther.mValue.mURL);
+    }
     else if (eCSSUnit_Pair == mUnit) {
       return *mValue.mPair == *aOther.mValue.mPair;
     }
     else if (eCSSUnit_List == mUnit) {
       return nsCSSValueList::Equal(mValue.mList, aOther.mValue.mList);
     }
     else if (eCSSUnit_SharedList == mUnit) {
       return *mValue.mSharedList == *aOther.mValue.mSharedList;
     }
     else if (eCSSUnit_PairList == mUnit) {
       return nsCSSValuePairList::Equal(mValue.mPairList,
                                        aOther.mValue.mPairList);
     }
+    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;
@@ -281,24 +345,28 @@ nscoord nsCSSValue::GetPixelLength() con
 }
 
 void nsCSSValue::DoReset()
 {
   if (UnitHasStringValue()) {
     mValue.mString->Release();
   } else if (UnitHasArrayValue()) {
     DO_RELEASE(mArray);
+  } else if (eCSSUnit_URL == mUnit) {
+    DO_RELEASE(mURL);
   } else if (eCSSUnit_Pair == mUnit) {
     DO_RELEASE(mPair);
   } else if (eCSSUnit_List == mUnit) {
     DO_RELEASE(mList);
   } else if (eCSSUnit_SharedList == mUnit) {
     DO_RELEASE(mSharedList);
   } else if (eCSSUnit_PairList == mUnit) {
     DO_RELEASE(mPairList);
+  } else if (eCSSUnit_GridTemplateAreas == mUnit) {
+    DO_RELEASE(mGridTemplateAreas);
   } else if (eCSSUnit_FontFamilyList == mUnit) {
     DO_RELEASE(mFontFamilyList);
   } else if (eCSSUnit_AtomIdent == mUnit) {
     DO_RELEASE(mAtom);
   }
   mUnit = eCSSUnit_Null;
 }
 
@@ -364,16 +432,60 @@ void nsCSSValue::SetArrayValue(nsCSSValu
 {
   Reset();
   mUnit = aUnit;
   MOZ_ASSERT(UnitHasArrayValue(), "bad unit");
   mValue.mArray = aValue;
   mValue.mArray->AddRef();
 }
 
+void nsCSSValue::SetURLValue(mozilla::css::URLValue* aValue)
+{
+  Reset();
+  mUnit = eCSSUnit_URL;
+  mValue.mURL = aValue;
+  mValue.mURL->AddRef();
+}
+
+void nsCSSValue::SetGridTemplateAreas(mozilla::css::GridTemplateAreasValue* aValue)
+{
+  Reset();
+  mUnit = eCSSUnit_GridTemplateAreas;
+  mValue.mGridTemplateAreas = aValue;
+  mValue.mGridTemplateAreas->AddRef();
+}
+
+void nsCSSValue::SetFontFamilyListValue(already_AddRefed<SharedFontList> aValue)
+{
+  Reset();
+  mUnit = eCSSUnit_FontFamilyList;
+  mValue.mFontFamilyList = aValue.take();
+}
+
+void nsCSSValue::SetFontStretch(FontStretch aStretch)
+{
+  Reset();
+  mUnit = eCSSUnit_FontStretch;
+  mValue.mFontStretch = aStretch;
+}
+
+void nsCSSValue::SetFontSlantStyle(FontSlantStyle aStyle)
+{
+  Reset();
+  mUnit = eCSSUnit_FontSlantStyle;
+  mValue.mFontSlantStyle = aStyle;
+}
+
+void nsCSSValue::SetFontWeight(FontWeight aWeight)
+{
+  Reset();
+  mUnit = eCSSUnit_FontWeight;
+  mValue.mFontWeight = aWeight;
+}
+
 void nsCSSValue::SetPairValue(const nsCSSValuePair* aValue)
 {
   // 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 &&
@@ -418,50 +530,148 @@ nsCSSValueList* nsCSSValue::SetListValue
 void nsCSSValue::SetSharedListValue(nsCSSValueSharedList* aList)
 {
   Reset();
   mUnit = eCSSUnit_SharedList;
   mValue.mSharedList = aList;
   mValue.mSharedList->AddRef();
 }
 
+void nsCSSValue::SetDependentListValue(nsCSSValueList* aList)
+{
+  Reset();
+  if (aList) {
+    mUnit = eCSSUnit_ListDep;
+    mValue.mListDependent = aList;
+  }
+}
+
+void
+nsCSSValue::AdoptListValue(UniquePtr<nsCSSValueList> aValue)
+{
+  // We have to copy the first element since for owned lists the first
+  // element should be an nsCSSValueList_heap object.
+  SetListValue();
+  mValue.mList->mValue = std::move(aValue->mValue);
+  mValue.mList->mNext  = aValue->mNext;
+  aValue->mNext = nullptr;
+  aValue.reset();
+}
+
 nsCSSValuePairList* nsCSSValue::SetPairListValue()
 {
   Reset();
   mUnit = eCSSUnit_PairList;
   mValue.mPairList = new nsCSSValuePairList_heap;
   mValue.mPairList->AddRef();
   return mValue.mPairList;
 }
 
+void nsCSSValue::SetDependentPairListValue(nsCSSValuePairList* aList)
+{
+  Reset();
+  if (aList) {
+    mUnit = eCSSUnit_PairListDep;
+    mValue.mPairListDependent = aList;
+  }
+}
+
+void
+nsCSSValue::AdoptPairListValue(UniquePtr<nsCSSValuePairList> aValue)
+{
+  // We have to copy the first element, since for owned pair lists, the first
+  // element should be an nsCSSValuePairList_heap object.
+  SetPairListValue();
+  mValue.mPairList->mXValue = std::move(aValue->mXValue);
+  mValue.mPairList->mYValue = std::move(aValue->mYValue);
+  mValue.mPairList->mNext   = aValue->mNext;
+  aValue->mNext = nullptr;
+  aValue.reset();
+}
+
+void nsCSSValue::SetAutoValue()
+{
+  Reset();
+  mUnit = eCSSUnit_Auto;
+}
+
+void nsCSSValue::SetInheritValue()
+{
+  Reset();
+  mUnit = eCSSUnit_Inherit;
+}
+
+void nsCSSValue::SetInitialValue()
+{
+  Reset();
+  mUnit = eCSSUnit_Initial;
+}
+
+void nsCSSValue::SetUnsetValue()
+{
+  Reset();
+  mUnit = eCSSUnit_Unset;
+}
+
 void nsCSSValue::SetNoneValue()
 {
   Reset();
   mUnit = eCSSUnit_None;
 }
 
-void nsCSSValue::SetCalcValue(const nsStyleCoord::CalcValue& aCalc)
+void nsCSSValue::SetAllValue()
+{
+  Reset();
+  mUnit = eCSSUnit_All;
+}
+
+void nsCSSValue::SetNormalValue()
+{
+  Reset();
+  mUnit = eCSSUnit_Normal;
+}
+
+void nsCSSValue::SetSystemFontValue()
+{
+  Reset();
+  mUnit = eCSSUnit_System_Font;
+}
+
+void nsCSSValue::SetDummyValue()
+{
+  Reset();
+  mUnit = eCSSUnit_Dummy;
+}
+
+void nsCSSValue::SetDummyInheritValue()
+{
+  Reset();
+  mUnit = eCSSUnit_DummyInherit;
+}
+
+void nsCSSValue::SetCalcValue(const nsStyleCoord::CalcValue* aCalc)
 {
   RefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(1);
-  if (!aCalc.mHasPercent) {
-    arr->Item(0).SetIntegerCoordValue(aCalc.mLength);
+  if (!aCalc->mHasPercent) {
+    arr->Item(0).SetIntegerCoordValue(aCalc->mLength);
   } else {
-    nsCSSValue::Array* arr2 = nsCSSValue::Array::Create(2);
+    nsCSSValue::Array *arr2 = nsCSSValue::Array::Create(2);
     arr->Item(0).SetArrayValue(arr2, eCSSUnit_Calc_Plus);
-    arr2->Item(0).SetIntegerCoordValue(aCalc.mLength);
-    arr2->Item(1).SetPercentValue(aCalc.mPercent);
+    arr2->Item(0).SetIntegerCoordValue(aCalc->mLength);
+    arr2->Item(1).SetPercentValue(aCalc->mPercent);
   }
 
   SetArrayValue(arr, eCSSUnit_Calc);
 }
 
 nsStyleCoord::CalcValue
 nsCSSValue::GetCalcValue() const
 {
-  MOZ_ASSERT(mUnit == eCSSUnit_Calc, "The unit should be eCSSUnit_Calc");
+  MOZ_ASSERT(mUnit == eCSSUnit_Calc,
+             "The unit should be eCSSUnit_Calc");
 
   const nsCSSValue::Array* array = GetArrayValue();
   MOZ_ASSERT(array->Count() == 1,
              "There should be a 1-length array");
 
   const nsCSSValue& rootValue = array->Item(0);
 
   nsStyleCoord::CalcValue result;
@@ -487,16 +697,41 @@ nsCSSValue::GetCalcValue() const
     result.mLength = length.GetPixelLength();
     result.mPercent = percent.GetPercentValue();
     result.mHasPercent = true;
   }
 
   return result;
 }
 
+nsCSSValue::Array*
+nsCSSValue::InitFunction(nsCSSKeyword aFunctionId, uint32_t aNumArgs)
+{
+  RefPtr<nsCSSValue::Array> func = Array::Create(aNumArgs + 1);
+  func->Item(0).SetIntValue(aFunctionId, eCSSUnit_Enumerated);
+  SetArrayValue(func, eCSSUnit_Function);
+  return func;
+}
+
+bool
+nsCSSValue::EqualsFunction(nsCSSKeyword aFunctionId) const
+{
+  if (mUnit != eCSSUnit_Function) {
+    return false;
+  }
+
+  nsCSSValue::Array* func = mValue.mArray;
+  MOZ_ASSERT(func && func->Count() >= 1 &&
+             func->Item(0).GetUnit() == eCSSUnit_Enumerated,
+             "illegally structured function value");
+
+  nsCSSKeyword thisFunctionId = func->Item(0).GetKeywordValue();
+  return thisFunctionId == aFunctionId;
+}
+
 // static
 already_AddRefed<nsStringBuffer>
 nsCSSValue::BufferFromString(const nsString& aValue)
 {
   RefPtr<nsStringBuffer> buffer = nsStringBuffer::FromString(aValue);
   if (buffer) {
     return buffer.forget();
   }
@@ -513,16 +748,26 @@ nsCSSValue::BufferFromString(const nsStr
 
   char16_t* data = static_cast<char16_t*>(buffer->Data());
   nsCharTraits<char16_t>::copy(data, aValue.get(), length);
   // Null-terminate.
   data[length] = 0;
   return buffer.forget();
 }
 
+void
+nsCSSValue::AtomizeIdentValue()
+{
+  MOZ_ASSERT(mUnit == eCSSUnit_Ident);
+  RefPtr<nsAtom> atom = NS_Atomize(GetStringBufferValue());
+  Reset();
+  mUnit = eCSSUnit_AtomIdent;
+  mValue.mAtom = atom.forget().take();
+}
+
 /* static */ void
 nsCSSValue::AppendAlignJustifyValueToString(int32_t aValue, nsAString& aResult)
 {
   auto legacy = aValue & NS_STYLE_ALIGN_LEGACY;
   if (legacy) {
     aValue &= ~legacy;
     aResult.AppendLiteral("legacy");
     if (!aValue) {
@@ -573,16 +818,18 @@ nsCSSValue::SizeOfExcludingThis(mozilla:
     case eCSSUnit_Dummy:
     case eCSSUnit_DummyInherit:
       break;
 
     // String
     case eCSSUnit_String:
     case eCSSUnit_Ident:
     case eCSSUnit_Attr:
+    case eCSSUnit_Local_Font:
+    case eCSSUnit_Font_Format:
     case eCSSUnit_Element:
       n += mValue.mString->SizeOfIncludingThisIfUnshared(aMallocSizeOf);
       break;
 
     // Array
     case eCSSUnit_Array:
     case eCSSUnit_Counter:
     case eCSSUnit_Counters:
@@ -593,16 +840,21 @@ nsCSSValue::SizeOfExcludingThis(mozilla:
     case eCSSUnit_Calc:
     case eCSSUnit_Calc_Plus:
     case eCSSUnit_Calc_Minus:
     case eCSSUnit_Calc_Times_L:
     case eCSSUnit_Calc_Times_R:
     case eCSSUnit_Calc_Divided:
       break;
 
+    // URL
+    case eCSSUnit_URL:
+      n += mValue.mURL->SizeOfIncludingThis(aMallocSizeOf);
+      break;
+
     // Pair
     case eCSSUnit_Pair:
       n += mValue.mPair->SizeOfIncludingThis(aMallocSizeOf);
       break;
 
     // List
     case eCSSUnit_List:
       n += mValue.mList->SizeOfIncludingThis(aMallocSizeOf);
@@ -622,30 +874,38 @@ nsCSSValue::SizeOfExcludingThis(mozilla:
     case eCSSUnit_PairList:
       n += mValue.mPairList->SizeOfIncludingThis(aMallocSizeOf);
       break;
 
     // PairListDep: not measured because it's non-owning.
     case eCSSUnit_PairListDep:
       break;
 
+    // GridTemplateAreas
+    case eCSSUnit_GridTemplateAreas:
+      n += mValue.mGridTemplateAreas->SizeOfIncludingThis(aMallocSizeOf);
+      break;
+
     case eCSSUnit_FontFamilyList:
       // The SharedFontList is a refcounted object, but is unique per
       // declaration. We don't measure the references from computed
       // values.
       n += mValue.mFontFamilyList->SizeOfIncludingThis(aMallocSizeOf);
       break;
 
     // 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
@@ -331,17 +331,19 @@ enum nsCSSUnit {
   eCSSUnit_Dummy        = 9,      // (n/a) a fake but specified value, used
                                   //       only in temporary values
   eCSSUnit_DummyInherit = 10,     // (n/a) a fake but specified value, used
                                   //       only in temporary values
 
   eCSSUnit_String       = 11,     // (char16_t*) a string value
   eCSSUnit_Ident        = 12,     // (char16_t*) a string value
   eCSSUnit_Attr         = 14,     // (char16_t*) a attr(string) value
-  eCSSUnit_Element      = 15,     // (char16_t*) an element id
+  eCSSUnit_Local_Font   = 15,     // (char16_t*) a local font name
+  eCSSUnit_Font_Format  = 16,     // (char16_t*) a font format name
+  eCSSUnit_Element      = 17,     // (char16_t*) an element id
 
   eCSSUnit_Array        = 20,     // (nsCSSValue::Array*) a list of values
   eCSSUnit_Counter      = 21,     // (nsCSSValue::Array*) a counter(string,[string]) value
   eCSSUnit_Counters     = 22,     // (nsCSSValue::Array*) a counters(string,string[,string]) value
   eCSSUnit_Cubic_Bezier = 23,     // (nsCSSValue::Array*) a list of float values
   eCSSUnit_Steps        = 24,     // (nsCSSValue::Array*) a list of (integer, enumerated)
   eCSSUnit_Symbols      = 25,     // (nsCSSValue::Array*) a symbols(enumerated, symbols) value
   eCSSUnit_Function     = 26,     // (nsCSSValue::Array*) a function with
@@ -361,16 +363,20 @@ enum nsCSSUnit {
   // Plus, Minus, Times_* and Divided have arrays with exactly 2
   // elements.  a + b + c + d is grouped as ((a + b) + c) + d
   eCSSUnit_Calc_Plus    = 31,     // (nsCSSValue::Array*) + node within calc()
   eCSSUnit_Calc_Minus   = 32,     // (nsCSSValue::Array*) - within calc
   eCSSUnit_Calc_Times_L = 33,     // (nsCSSValue::Array*) num * val within calc
   eCSSUnit_Calc_Times_R = 34,     // (nsCSSValue::Array*) val * num within calc
   eCSSUnit_Calc_Divided = 35,     // (nsCSSValue::Array*) / within calc
 
+  eCSSUnit_URL          = 40,     // (nsCSSValue::URL*) value
+  eCSSUnit_GridTemplateAreas   = 44,   // (GridTemplateAreasValue*)
+                                       // for grid-template-areas
+
   eCSSUnit_Pair         = 50,     // (nsCSSValuePair*) pair of values
   eCSSUnit_List         = 53,     // (nsCSSValueList*) list of values
   eCSSUnit_ListDep      = 54,     // (nsCSSValueList*) same as List
                                   //   but does not own the list
   eCSSUnit_SharedList   = 55,     // (nsCSSValueSharedList*) same as list
                                   //   but reference counted and shared
   eCSSUnit_PairList     = 56,     // (nsCSSValuePairList*) list of value pairs
   eCSSUnit_PairListDep  = 57,     // (nsCSSValuePairList*) same as PairList
@@ -420,45 +426,58 @@ 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;
 struct nsCSSValuePairList_heap;
 
 class nsCSSValue {
 public:
   struct Array;
   friend struct Array;
 
+  friend struct mozilla::css::URLValueData;
+
   friend struct mozilla::css::ImageValue;
 
   // for valueless units only (null, auto, inherit, none, all, normal)
   explicit nsCSSValue(nsCSSUnit aUnit = eCSSUnit_Null)
     : mUnit(aUnit)
   {
     MOZ_ASSERT(aUnit <= eCSSUnit_DummyInherit, "not a valueless unit");
   }
 
   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,
@@ -581,41 +600,80 @@ public:
   }
 
   Array* GetArrayValue() const
   {
     MOZ_ASSERT(UnitHasArrayValue(), "not an array value");
     return mValue.mArray;
   }
 
+  nsIURI* GetURLValue() const
+  {
+    MOZ_ASSERT(mUnit == eCSSUnit_URL, "not a URL value");
+    return mValue.mURL->GetURI();
+  }
+
   nsCSSValueSharedList* GetSharedListValue() const
   {
     MOZ_ASSERT(mUnit == eCSSUnit_SharedList, "not a shared list value");
     return mValue.mSharedList;
   }
 
   mozilla::NotNull<mozilla::SharedFontList*> GetFontFamilyListValue() const
   {
     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();
   inline const nsCSSValuePairList* GetPairListValue() const;
 
+  mozilla::css::URLValue* GetURLStructValue() const
+  {
+    // Not allowing this for Image values, because if the caller takes
+    // a ref to them they won't be able to delete them properly.
+    MOZ_ASSERT(mUnit == eCSSUnit_URL, "not a URL value");
+    return mValue.mURL;
+  }
+
+  mozilla::css::GridTemplateAreasValue* GetGridTemplateAreas() const
+  {
+    MOZ_ASSERT(mUnit == eCSSUnit_GridTemplateAreas,
+               "not a grid-template-areas value");
+    return mValue.mGridTemplateAreas;
+  }
+
   // Not making this inline because that would force us to include
   // imgIRequest.h, which leads to REQUIRES hell, since this header is included
   // all over.
   imgRequestProxy* GetImageValue(nsIDocument* aDocument) const;
 
   // Like GetImageValue, but additionally will pass the imgRequestProxy
   // through nsContentUtils::GetStaticRequest if aPresContent is static.
   already_AddRefed<imgRequestProxy> GetPossiblyStaticImageValue(
@@ -648,30 +706,60 @@ public:
   }
   void SetPercentValue(float aValue);
   void SetFloatValue(float aValue, nsCSSUnit aUnit);
   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 SetDependentListValue(nsCSSValueList* aList);
+  void SetDependentPairListValue(nsCSSValuePairList* aList);
+  void SetAutoValue();
+  void SetInheritValue();
+  void SetInitialValue();
+  void SetUnsetValue();
   void SetNoneValue();
+  void SetAllValue();
+  void SetNormalValue();
+  void SetSystemFontValue();
+  void SetDummyValue();
+  void SetDummyInheritValue();
+
+  // Converts an nsStyleCoord::CalcValue back into a CSSValue
+  void SetCalcValue(const nsStyleCoord::CalcValue* aCalc);
 
   nsStyleCoord::CalcValue GetCalcValue() const;
-  void SetCalcValue(const nsStyleCoord::CalcValue&);
 
   // These are a little different - they allocate storage for you and
   // return a handle.
   nsCSSValueList* SetListValue();
   nsCSSValuePairList* SetPairListValue();
 
+  // These take ownership of the passed-in resource.
+  void AdoptListValue(mozilla::UniquePtr<nsCSSValueList> aValue);
+  void AdoptPairListValue(mozilla::UniquePtr<nsCSSValuePairList> aValue);
+
+  void StartImageLoad(nsIDocument* aDocument,
+                      mozilla::CORSMode aCORSMode) const;  // Only pretend const
+
+  // Initializes as a function value with the specified function id.
+  Array* InitFunction(nsCSSKeyword aFunctionId, uint32_t aNumArgs);
+  // Checks if this is a function value with the specified function id.
+  bool EqualsFunction(nsCSSKeyword aFunctionId) const;
+
   // Returns an already addrefed buffer.  Guaranteed to return non-null.
   // (Will abort on allocation failure.)
   static already_AddRefed<nsStringBuffer>
     BufferFromString(const nsString& aValue);
 
   // Convert the given Ident value into AtomIdent.
   void AtomizeIdentValue();
 
@@ -690,23 +778,28 @@ protected:
   union {
     int32_t    mInt;
     float      mFloat;
     // Note: the capacity of the buffer may exceed the length of the string.
     // If we're of a string type, mString is not null.
     nsStringBuffer* MOZ_OWNING_REF mString;
     nsAtom* MOZ_OWNING_REF mAtom;
     Array* MOZ_OWNING_REF mArray;
+    mozilla::css::URLValue* MOZ_OWNING_REF mURL;
+    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;
-  StyleFontDisplay fontDisplay = GetFontDisplay();
-  if (fontDisplay == StyleFontDisplay::Auto ||
-      fontDisplay == StyleFontDisplay::Block) {
+  uint8_t fontDisplay = GetFontDisplay();
+  if (fontDisplay == NS_FONT_DISPLAY_AUTO ||
+      fontDisplay == NS_FONT_DISPLAY_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();
-  StyleFontDisplay fontDisplay = loader->GetFontDisplay();
+  uint8_t 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 StyleFontDisplay::Auto:
-    case StyleFontDisplay::Block:
+    case NS_FONT_DISPLAY_AUTO:
+    case NS_FONT_DISPLAY_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 StyleFontDisplay::Swap:
+    case NS_FONT_DISPLAY_SWAP:
       ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_SLOWLY;
       break;
-    case StyleFontDisplay::Fallback: {
+    case NS_FONT_DISPLAY_FALLBACK: {
       if (ufe->mFontDataLoadingState == gfxUserFontEntry::LOADING_STARTED) {
         ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_SLOWLY;
       } else {
         ufe->mFontDataLoadingState = gfxUserFontEntry::LOADING_TIMED_OUT;
         updateUserFontSet = false;
       }
       break;
     }
-    case StyleFontDisplay::Optional:
+    case NS_FONT_DISPLAY_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, static_cast<int>(fontDisplay)));
+             loader, ctx, 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() == StyleFontDisplay::Fallback) {
+  if (GetFontDisplay() == NS_FONT_DISPLAY_FALLBACK) {
     uint32_t loadTimeout = GetFallbackDelay();
     if (downloadTimeMS > loadTimeout &&
         (mUserFontEntry->mFontDataLoadingState ==
          gfxUserFontEntry::LOADING_SLOWLY)) {
       mUserFontEntry->mFontDataLoadingState =
         gfxUserFontEntry::LOADING_TIMED_OUT;
     }
   }
@@ -328,16 +328,17 @@ nsFontFaceLoader::Cancel()
   mFontFaceSet = nullptr;
   if (mLoadTimer) {
     mLoadTimer->Cancel();
     mLoadTimer = nullptr;
   }
   mChannel->Cancel(NS_BINDING_ABORTED);
 }
 
-StyleFontDisplay
+uint8_t
 nsFontFaceLoader::GetFontDisplay()
 {
-  if (!StaticPrefs::layout_css_font_display_enabled()) {
-    return StyleFontDisplay::Auto;
+  uint8_t fontDisplay = NS_FONT_DISPLAY_AUTO;
+  if (StaticPrefs::layout_css_font_display_enabled()) {
+    fontDisplay = mUserFontEntry->GetFontDisplay();
   }
-  return mUserFontEntry->GetFontDisplay();
+  return fontDisplay;
 }
--- 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
-  mozilla::StyleFontDisplay GetFontDisplay();
+  uint8_t 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,54 +1,33 @@
 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",
-  "StyleFontDisplay",
-  "StyleFontFaceSourceListComponent",
-  "StyleFontLanguageOverride",
-  "StylePathCommand",
-  "StyleUnicodeRange",
+  "StylePathCommand"
 ]
 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};
+use values::specified::font::{AbsoluteFontWeight, FontStretch as SpecifiedFontStretch};
 #[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,29 +40,16 @@ 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.
@@ -92,126 +79,73 @@ 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)]
-pub struct FontWeightRange(pub AbsoluteFontWeight, pub AbsoluteFontWeight);
-impl_range!(FontWeightRange, AbsoluteFontWeight);
+#[derive(Clone, Debug, PartialEq, ToCss)]
+pub struct FontWeight(pub AbsoluteFontWeight, pub Option<AbsoluteFontWeight>);
 
-/// 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)
+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 font-stretch descriptor:
 ///
 /// https://drafts.csswg.org/css-fonts-4/#descdef-font-face-font-stretch
-#[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);
+#[derive(Clone, Debug, PartialEq, ToCss)]
+pub struct FontStretch(pub SpecifiedFontStretch, pub Option<SpecifiedFontStretch>);
 
-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))
+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))
     }
 }
 
 /// 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,
@@ -246,32 +180,16 @@ 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 {
@@ -536,20 +454,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: FontWeightRange,
+        "font-weight" weight / mWeight: FontWeight,
 
         /// The stretch of this font face.
-        "font-stretch" stretch / mStretch: FontStretchRange,
+        "font-stretch" stretch / mStretch: FontStretch,
 
         /// 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,17 +1,209 @@
 /* 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 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,
+            }
+        });
+        let mut target_srcs = nscssvalue
+            .set_array(src_len as i32)
+            .as_mut_slice()
+            .iter_mut();
+        macro_rules! next {
+            () => {
+                target_srcs
+                    .next()
+                    .expect("Length of target_srcs should be enough")
+            };
+        }
+        for src in self.iter() {
+            match *src {
+                Source::Url(ref url) => {
+                    next!().set_url(&url.url);
+                    for hint in url.format_hints.iter() {
+                        next!().set_font_format(&hint);
+                    }
+                },
+                Source::Local(ref family) => {
+                    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),
--- a/servo/components/style/gecko_bindings/sugar/ns_css_value.rs
+++ b/servo/components/style/gecko_bindings/sugar/ns_css_value.rs
@@ -9,16 +9,17 @@ use gecko_bindings::structs;
 use gecko_bindings::structs::{nsCSSUnit, nsCSSValue};
 use gecko_bindings::structs::{nsCSSValueList, nsCSSValue_Array};
 use gecko_string_cache::Atom;
 use std::marker::PhantomData;
 use std::mem;
 use std::ops::{Index, IndexMut};
 use std::slice;
 use values::computed::{Angle, Length, LengthOrPercentage, Percentage};
+use values::specified::url::SpecifiedUrl;
 
 impl nsCSSValue {
     /// Create a CSSValue with null unit, useful to be used as a return value.
     #[inline]
     pub fn null() -> Self {
         unsafe { mem::zeroed() }
     }
 
@@ -161,16 +162,41 @@ impl nsCSSValue {
         self.set_string_internal(s, nsCSSUnit::eCSSUnit_Ident)
     }
 
     /// Set to an atom identifier value
     pub fn set_atom_ident(&mut self, s: Atom) {
         unsafe { bindings::Gecko_CSSValue_SetAtomIdent(self, s.into_addrefed()) }
     }
 
+    /// Set to a font format.
+    pub fn set_font_format(&mut self, s: &str) {
+        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)
     }
@@ -180,16 +206,21 @@ impl nsCSSValue {
         self.set_int_internal(value.into(), nsCSSUnit::eCSSUnit_Enumerated);
     }
 
     /// Set to a number value
     pub fn set_number(&mut self, number: f32) {
         unsafe { bindings::Gecko_CSSValue_SetFloat(self, number, nsCSSUnit::eCSSUnit_Number) }
     }
 
+    /// Set to a url value
+    pub fn set_url(&mut self, url: &SpecifiedUrl) {
+        unsafe { bindings::Gecko_CSSValue_SetURL(self, url.url_value.get()) }
+    }
+
     /// Set to an array of given length
     pub fn set_array(&mut self, len: i32) -> &mut nsCSSValue_Array {
         unsafe { bindings::Gecko_CSSValue_SetArray(self, len) }
         unsafe { self.mValue.mArray.as_mut().as_mut() }.unwrap()
     }
 
     /// Generic set from any value that implements the ToNsCssValue trait.
     pub fn set_from<T: ToNsCssValue>(&mut self, value: T) {
--- a/servo/components/style/values/computed/font.rs
+++ b/servo/components/style/values/computed/font.rs
@@ -742,17 +742,16 @@ 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,17 +22,16 @@ 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,26 +287,24 @@ 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 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))
+    /// 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),
+        )
     }
 
     /// 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)?;
@@ -377,17 +375,16 @@ 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`.
@@ -2055,50 +2052,38 @@ 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,171 +2476,49 @@ 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();
     })
 }
 
-
-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(
+#[no_mangle]
+pub unsafe extern "C" fn Servo_FontFaceRule_GetDescriptor(
     rule: RawServoFontFaceRuleBorrowed,
-) -> *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;
+    desc: nsCSSFontDesc,
+    result: nsCSSValueBorrowedMut,
+) {
     read_locked_arc(rule, |rule: &FontFaceRule| {
-        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(),
-                            });
+        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);
+                            }
                         }
-                    }
-                    Source::Local(ref name) => {
-                        set_next(FontFaceSourceListComponent::Local(name.name.as_ptr()));
-                    }
+                    )*
+                    $(
+                        nsCSSFontDesc::$i_enum_name => {
+                            debug_assert!(false, "not a valid font descriptor");
+                        }
+                    )*
                 }
             }
         }
-
-        assert!(iter.next().is_none(), "miscalculated");
+        apply_font_desc_list!(to_css_value)
     })
 }
 
 #[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 {
@@ -5756,83 +5634,79 @@ 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 unsafe extern "C" fn Servo_ParseFontShorthandForMatching(
+pub extern "C" fn Servo_ParseFontShorthandForMatching(
     value: *const nsAString,
     data: *mut URLExtraData,
     family: *mut structs::RefPtr<structs::SharedFontList>,
-    style: *mut structs::StyleComputedFontStyleDescriptor,
-    stretch: *mut f32,
-    weight: *mut f32,
+    style: nsCSSValueBorrowedMut,
+    stretch: nsCSSValueBorrowedMut,
+    weight: nsCSSValueBorrowedMut
 ) -> bool {
-    use style::font_face::ComputedFontStyleDescriptor;
     use style::properties::shorthands::font;
     use style::values::generics::font::FontStyle as GenericFontStyle;
-    use style::values::computed::font::FontWeight as ComputedFontWeight;
-    use style::values::specified::font::{FontFamily, FontWeight, FontStretch, FontStyle, SpecifiedFontStyle};
-
-    let string = (*value).to_string();
+    use style::values::specified::font::{FontFamily, FontWeight, FontStyle, SpecifiedFontStyle};
+
+    let string = unsafe { (*value).to_string() };
     let mut input = ParserInput::new(&string);
     let mut parser = Parser::new(&mut input);
-    let url_data = UrlExtraData::from_ptr_ref(&data);
+    let url_data = unsafe { 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 = &mut *family;
+    let family = unsafe { &mut *family };
     match font.font_family {
         FontFamily::Values(list) => family.set_move(list.0),
         FontFamily::System(_) => return false,
     }
 
     let specified_font_style = match font.font_style {
         FontStyle::Specified(ref s) => s,
         FontStyle::System(_) => return false,
     };
-    *style = ::std::mem::transmute(match *specified_font_style {
-        GenericFontStyle::Normal => ComputedFontStyleDescriptor::Normal,
-        GenericFontStyle::Italic => ComputedFontStyleDescriptor::Italic,
+    match *specified_font_style {
+        GenericFontStyle::Normal => style.set_normal(),
+        GenericFontStyle::Italic => style.set_enum(structs::NS_FONT_STYLE_ITALIC as i32),
         GenericFontStyle::Oblique(ref angle) => {
-            let angle = SpecifiedFontStyle::compute_angle_degrees(angle);
-            ComputedFontStyleDescriptor::Oblique(angle, angle)
+            style.set_font_style(SpecifiedFontStyle::compute_angle(angle).degrees())
         }
-    });
-
-    *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,
+    }
+
+    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),
         // Resolve relative font weights against the initial of font-weight
         // (normal, which is equivalent to 400).
-        FontWeight::Bolder => ComputedFontWeight::normal().bolder().0,
-        FontWeight::Lighter => ComputedFontWeight::normal().lighter().0,
+        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::System(_) => return false,
-    };
+    }
 
     true
 }
 
 #[no_mangle]
 pub unsafe extern "C" fn Servo_SourceSizeList_Parse(
     value: *const nsACString,
 ) -> *mut RawServoSourceSizeList {
--- a/taskcluster/scripts/misc/build-cbindgen.sh
+++ b/taskcluster/scripts/misc/build-cbindgen.sh
@@ -1,14 +1,14 @@
 #!/bin/bash
 set -x -e -v
 
 # If you update this, make sure to update the minimum version in rust.configure
 # as well.
-CBINDGEN_VERSION=v0.6.4
+CBINDGEN_VERSION=v0.6.2
 TARGET="$1"
 
 case "$(uname -s)" in
 Linux)
     WORKSPACE=$HOME/workspace
     UPLOAD_DIR=$HOME/artifacts
     COMPRESS_EXT=xz
     ;;