Bug 1561738 - Use cbindgen for grid track sizing. r=boris
authorEmilio Cobos Álvarez <emilio@crisal.io>
Fri, 28 Jun 2019 09:46:02 +0000
changeset 480514 40121b4494a089598a1c16421ed5f85b33fb7e9d
parent 480513 51dd2e169f3fdcb3a834e7e620f312ee8434ee16
child 480515 ad438d2a0a154498e428740aece0db242955e8cd
push id36214
push usercsabou@mozilla.com
push dateFri, 28 Jun 2019 16:12:48 +0000
treeherdermozilla-central@8537d24d8aa8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersboris
bugs1561738
milestone69.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1561738 - Use cbindgen for grid track sizing. r=boris Differential Revision: https://phabricator.services.mozilla.com/D36118
layout/generic/nsGridContainerFrame.cpp
layout/style/GeckoBindings.cpp
layout/style/ServoBindings.toml
layout/style/nsComputedDOMStyle.cpp
layout/style/nsComputedDOMStyle.h
layout/style/nsStyleCoord.h
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
servo/components/style/gecko/conversions.rs
servo/components/style/gecko/values.rs
servo/components/style/properties/gecko.mako.rs
servo/components/style/values/computed/mod.rs
servo/components/style/values/generics/grid.rs
servo/components/style/values/specified/grid.rs
servo/ports/geckolib/cbindgen.toml
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -54,16 +54,46 @@ static const nsFrameState kIsSubgridBits
 
 // https://drafts.csswg.org/css-sizing/#constraints
 enum class SizingConstraint {
   MinContent,   // sizing under min-content constraint
   MaxContent,   // sizing under max-content constraint
   NoConstraint  // no constraint, used during Reflow
 };
 
+namespace mozilla {
+
+template <>
+inline const StyleTrackBreadth& StyleTrackSize::GetMax() const {
+  if (IsBreadth()) {
+    return AsBreadth();
+  }
+  if (IsMinmax()) {
+    return AsMinmax()._1;
+  }
+  MOZ_ASSERT(IsFitContent());
+  return AsFitContent();
+}
+
+template <>
+inline const StyleTrackBreadth& StyleTrackSize::GetMin() const {
+  static const StyleTrackBreadth kAuto = StyleTrackBreadth::Auto();
+  if (IsBreadth()) {
+    // <flex> behaves like minmax(auto, <flex>)
+    return AsBreadth().IsFr() ? kAuto : AsBreadth();
+  }
+  if (IsMinmax()) {
+    return AsMinmax()._0;
+  }
+  MOZ_ASSERT(IsFitContent());
+  return kAuto;
+}
+
+}
+
 static void ReparentFrame(nsIFrame* aFrame, nsContainerFrame* aOldParent,
                           nsContainerFrame* aNewParent) {
   NS_ASSERTION(aOldParent == aFrame->GetParent(),
                "Parent not consistent with expectations");
 
   aFrame->SetParent(aNewParent);
 
   // When pushing and pulling frames we need to check for whether any
@@ -111,23 +141,23 @@ static nscoord ClampToCSSMaxBSize(nscoor
 }
 
 template <typename Size>
 static bool IsPercentOfIndefiniteSize(const Size& aCoord,
                                       nscoord aPercentBasis) {
   return aPercentBasis == NS_UNCONSTRAINEDSIZE && aCoord.HasPercent();
 }
 
-static nscoord ResolveToDefiniteSize(const nsStyleCoord& aCoord,
+static nscoord ResolveToDefiniteSize(const StyleTrackBreadth& aBreadth,
                                      nscoord aPercentBasis) {
-  MOZ_ASSERT(aCoord.IsCoordPercentCalcUnit());
-  if (::IsPercentOfIndefiniteSize(aCoord, aPercentBasis)) {
+  MOZ_ASSERT(aBreadth.IsBreadth());
+  if (::IsPercentOfIndefiniteSize(aBreadth.AsBreadth(), aPercentBasis)) {
     return nscoord(0);
   }
-  return std::max(nscoord(0), aCoord.ComputeCoordPercentCalc(aPercentBasis));
+  return std::max(nscoord(0), aBreadth.AsBreadth().Resolve(aPercentBasis));
 }
 
 // Synthesize a baseline from a border box.  For an alphabetical baseline
 // this is the end edge of the border box.  For a central baseline it's
 // the center of the border box.
 // https://drafts.csswg.org/css-align-3/#synthesize-baselines
 // For a 'first baseline' the measure is from the border-box start edge and
 // for a 'last baseline' the measure is from the border-box end edge.
@@ -202,28 +232,22 @@ struct nsGridContainerFrame::TrackSize {
     eSkipGrowUnlimited2 =       0x400,
     eSkipGrowUnlimited = eSkipGrowUnlimited1 | eSkipGrowUnlimited2,
     eBreakBefore =              0x800,
     eFitContent =              0x1000,
     eInfinitelyGrowable =      0x2000,
     // clang-format on
   };
 
-  StateBits Initialize(nscoord aPercentageBasis, const nsStyleCoord& aMinCoord,
-                       const nsStyleCoord& aMaxCoord);
+  StateBits Initialize(nscoord aPercentageBasis, const StyleTrackSize&);
   bool IsFrozen() const { return mState & eFrozen; }
 #ifdef DEBUG
   void Dump() const;
 #endif
 
-  static bool IsMinContent(const nsStyleCoord& aCoord) {
-    return aCoord.GetUnit() == eStyleUnit_Enumerated &&
-           aCoord.GetEnumValue<StyleGridTrackBreadth>() ==
-               StyleGridTrackBreadth::MinContent;
-  }
   static bool IsDefiniteMaxSizing(StateBits aStateBits) {
     return (aStateBits & (eIntrinsicMaxSizing | eFlexMaxSizing)) == 0;
   }
 
   nscoord mBase;
   nscoord mLimit;
   nscoord mPosition;  // zero until we apply 'align/justify-content'
   // mBaselineSubtreeSize is the size of a baseline-aligned subtree within
@@ -235,76 +259,82 @@ struct nsGridContainerFrame::TrackSize {
 MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(TrackSize::StateBits)
 
 namespace mozilla {
 template <>
 struct IsPod<nsGridContainerFrame::TrackSize> : TrueType {};
 }  // namespace mozilla
 
 TrackSize::StateBits nsGridContainerFrame::TrackSize::Initialize(
-    nscoord aPercentageBasis, const nsStyleCoord& aMinCoord,
-    const nsStyleCoord& aMaxCoord) {
+    nscoord aPercentageBasis, const StyleTrackSize& aSize) {
+  using Tag = StyleTrackBreadth::Tag;
+
   MOZ_ASSERT(mBase == 0 && mLimit == 0 && mState == 0,
              "track size data is expected to be initialized to zero");
-  auto minSizeUnit = aMinCoord.GetUnit();
-  auto maxSizeUnit = aMaxCoord.GetUnit();
-  if (minSizeUnit == eStyleUnit_None) {
-    // This track is sized using fit-content(size) (represented in style system
-    // with minCoord=None,maxCoord=size).  In layout, fit-content(size) behaves
-    // as minmax(auto, max-content), with 'size' as an additional upper-bound.
+  mBaselineSubtreeSize[BaselineSharingGroup::First] = nscoord(0);
+  mBaselineSubtreeSize[BaselineSharingGroup::Last] = nscoord(0);
+
+  auto& min = aSize.GetMin();
+  auto& max = aSize.GetMax();
+
+  Tag minSizeTag = min.tag;
+  Tag maxSizeTag = max.tag;
+  if (aSize.IsFitContent()) {
+    // In layout, fit-content(size) behaves as minmax(auto, max-content), with
+    // 'size' as an additional upper-bound.
     mState = eFitContent;
-    minSizeUnit = eStyleUnit_Auto;
-    maxSizeUnit = eStyleUnit_Enumerated;  // triggers max-content sizing below
-  }
-  if (::IsPercentOfIndefiniteSize(aMinCoord, aPercentageBasis)) {
+    minSizeTag = Tag::Auto;
+    maxSizeTag = Tag::MaxContent;
+  }
+  if (::IsPercentOfIndefiniteSize(min, aPercentageBasis)) {
     // https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-percentage
     // "If the inline or block size of the grid container is indefinite,
     //  <percentage> values relative to that size are treated as 'auto'."
-    minSizeUnit = eStyleUnit_Auto;
-  }
-  if (::IsPercentOfIndefiniteSize(aMaxCoord, aPercentageBasis)) {
-    maxSizeUnit = eStyleUnit_Auto;
-  }
+    minSizeTag = Tag::Auto;
+  }
+  if (::IsPercentOfIndefiniteSize(max, aPercentageBasis)) {
+    maxSizeTag = Tag::Auto;
+  }
+
   // http://dev.w3.org/csswg/css-grid/#algo-init
-  switch (minSizeUnit) {
-    case eStyleUnit_Auto:
+  switch (minSizeTag) {
+    case Tag::Auto:
       mState |= eAutoMinSizing;
       break;
-    case eStyleUnit_Enumerated:
-      mState |=
-          IsMinContent(aMinCoord) ? eMinContentMinSizing : eMaxContentMinSizing;
+    case Tag::MinContent:
+      mState |= eMinContentMinSizing;
+      break;
+    case Tag::MaxContent:
+      mState |= eMaxContentMinSizing;
       break;
     default:
-      MOZ_ASSERT(minSizeUnit != eStyleUnit_FlexFraction,
-                 "<flex> min-sizing is invalid as a track size");
-      mBase = ::ResolveToDefiniteSize(aMinCoord, aPercentageBasis);
-  }
-  switch (maxSizeUnit) {
-    case eStyleUnit_Auto:
+      MOZ_ASSERT(!min.IsFr(), "<flex> min-sizing is invalid as a track size");
+      mBase = ::ResolveToDefiniteSize(min, aPercentageBasis);
+  }
+  switch (maxSizeTag) {
+    case Tag::Auto:
       mState |= eAutoMaxSizing;
       mLimit = NS_UNCONSTRAINEDSIZE;
       break;
-    case eStyleUnit_Enumerated:
-      mState |=
-          IsMinContent(aMaxCoord) ? eMinContentMaxSizing : eMaxContentMaxSizing;
+    case Tag::MinContent:
+    case Tag::MaxContent:
+      mState |= maxSizeTag == Tag::MinContent ? eMinContentMaxSizing
+                                              : eMaxContentMaxSizing;
       mLimit = NS_UNCONSTRAINEDSIZE;
       break;
-    case eStyleUnit_FlexFraction:
+    case Tag::Fr:
       mState |= eFlexMaxSizing;
       mLimit = mBase;
       break;
     default:
-      mLimit = ::ResolveToDefiniteSize(aMaxCoord, aPercentageBasis);
+      mLimit = ::ResolveToDefiniteSize(max, aPercentageBasis);
       if (mLimit < mBase) {
         mLimit = mBase;
       }
   }
-
-  mBaselineSubtreeSize[BaselineSharingGroup::First] = nscoord(0);
-  mBaselineSubtreeSize[BaselineSharingGroup::Last] = nscoord(0);
   return mState;
 }
 
 /**
  * Is aFrame1 a prev-continuation of aFrame2?
  */
 static bool IsPrevContinuationOf(nsIFrame* aFrame1, nsIFrame* aFrame2) {
   nsIFrame* prev = aFrame2;
@@ -1235,47 +1265,39 @@ class MOZ_STACK_CLASS nsGridContainerFra
   // True if there is a specified repeat(auto-fill/fit) track.
   const bool mHasRepeatAuto;
 };
 
 /**
  * Encapsulates CSS track-sizing functions.
  */
 struct nsGridContainerFrame::TrackSizingFunctions {
-  TrackSizingFunctions(const nsTArray<nsStyleCoord>& aMinSizingFunctions,
-                       const nsTArray<nsStyleCoord>& aMaxSizingFunctions,
-                       const nsStyleCoord& aAutoMinSizing,
-                       const nsStyleCoord& aAutoMaxSizing, bool aHasRepeatAuto,
+  TrackSizingFunctions(const nsTArray<StyleTrackSize>& aSizingFunctions,
+                       const StyleTrackSize& aAutoSizing, bool aHasRepeatAuto,
                        int32_t aRepeatAutoIndex)
-      : mMinSizingFunctions(aMinSizingFunctions),
-        mMaxSizingFunctions(aMaxSizingFunctions),
-        mAutoMinSizing(aAutoMinSizing),
-        mAutoMaxSizing(aAutoMaxSizing),
+      : mSizingFunctions(aSizingFunctions),
+        mAutoSizing(aAutoSizing),
         mExplicitGridOffset(0),
         mRepeatAutoStart(aHasRepeatAuto ? aRepeatAutoIndex : 0),
         mRepeatAutoEnd(mRepeatAutoStart),
         mRepeatEndDelta(0),
         mHasRepeatAuto(aHasRepeatAuto) {
-    MOZ_ASSERT(mMinSizingFunctions.Length() == mMaxSizingFunctions.Length());
     MOZ_ASSERT(!mHasRepeatAuto ||
-               (mMinSizingFunctions.Length() >= 1 &&
-                mRepeatAutoStart < mMinSizingFunctions.Length()));
+               (mSizingFunctions.Length() >= 1 &&
+                mRepeatAutoStart < mSizingFunctions.Length()));
   }
 
   TrackSizingFunctions(const nsStyleGridTemplate& aGridTemplate,
-                       const nsStyleCoord& aAutoMinSizing,
-                       const nsStyleCoord& aAutoMaxSizing)
+                       const StyleTrackSize& aAutoSizing)
       // Note: if mIsSubgrid is true below then the HasRepeatAuto bit is for
       // the mLineNameList, so we suppress that so that we can use this struct
       // also when it's true.  This can happen when a specified 'subgrid' has
       // no grid parent, which will behave as 'none'.
       : TrackSizingFunctions(
-            aGridTemplate.mMinTrackSizingFunctions,
-            aGridTemplate.mMaxTrackSizingFunctions, aAutoMinSizing,
-            aAutoMaxSizing,
+            aGridTemplate.mTrackSizingFunctions, aAutoSizing,
             !aGridTemplate.mIsSubgrid && aGridTemplate.HasRepeatAuto(),
             aGridTemplate.mRepeatAutoIndex) {}
 
   /**
    * Initialize the number of auto-fill/fit tracks to use and return that.
    * (zero if no auto-fill/fit track was specified)
    */
   uint32_t InitRepeatTracks(const NonNegativeLengthPercentageOrNormal& aGridGap,
@@ -1293,36 +1315,36 @@ struct nsGridContainerFrame::TrackSizing
 
   uint32_t CalculateRepeatFillCount(
       const NonNegativeLengthPercentageOrNormal& aGridGap, nscoord aMinSize,
       nscoord aSize, nscoord aMaxSize) const {
     if (!mHasRepeatAuto) {
       return 0;
     }
     // Spec quotes are from https://drafts.csswg.org/css-grid/#repeat-notation
-    const uint32_t numTracks = mMinSizingFunctions.Length();
+    const uint32_t numTracks = mSizingFunctions.Length();
     MOZ_ASSERT(numTracks >= 1, "expected at least the repeat() track");
     nscoord maxFill = aSize != NS_UNCONSTRAINEDSIZE ? aSize : aMaxSize;
     if (maxFill == NS_UNCONSTRAINEDSIZE && aMinSize == 0) {
       // "Otherwise, the specified track list repeats only once."
       return 1;
     }
     nscoord repeatTrackSize = 0;
     // Note that one repeat() track size is included in |sum| in this loop.
     nscoord sum = 0;
     const nscoord percentBasis = aSize;
     for (uint32_t i = 0; i < numTracks; ++i) {
       // "treating each track as its max track sizing function if that is
       // definite or as its minimum track sizing function otherwise"
       // https://drafts.csswg.org/css-grid/#valdef-repeat-auto-fill
-      const auto& maxCoord = mMaxSizingFunctions[i];
+      const auto& maxCoord = mSizingFunctions[i].GetMax();
       const auto* coord = &maxCoord;
-      if (!coord->IsCoordPercentCalcUnit()) {
-        coord = &mMinSizingFunctions[i];
-        if (!coord->IsCoordPercentCalcUnit()) {
+      if (!coord->IsBreadth()) {
+        coord = &mSizingFunctions[i].GetMin();
+        if (!coord->IsBreadth()) {
           return 1;
         }
       }
       nscoord trackSize = ::ResolveToDefiniteSize(*coord, percentBasis);
       if (i == mRepeatAutoStart) {
         // Use a minimum 1px for the repeat() track-size.
         if (trackSize < AppUnitsPerCSSPixel()) {
           trackSize = AppUnitsPerCSSPixel();
@@ -1365,67 +1387,57 @@ struct nsGridContainerFrame::TrackSizing
    */
   uint32_t ComputeExplicitGridEnd(uint32_t aGridTemplateAreasEnd) {
     uint32_t end = NumExplicitTracks() + 1;
     end = std::max(end, aGridTemplateAreasEnd);
     end = std::min(end, uint32_t(kMaxLine));
     return end;
   }
 
-  const nsStyleCoord& MinSizingFor(uint32_t aTrackIndex) const {
+  const StyleTrackSize& SizingFor(uint32_t aTrackIndex) const {
     if (MOZ_UNLIKELY(aTrackIndex < mExplicitGridOffset)) {
-      return mAutoMinSizing;
+      return mAutoSizing;
     }
     uint32_t index = aTrackIndex - mExplicitGridOffset;
     if (index >= mRepeatAutoStart) {
       if (index < mRepeatAutoEnd) {
-        return mMinSizingFunctions[mRepeatAutoStart];
+        return mSizingFunctions[mRepeatAutoStart];
       }
       index -= mRepeatEndDelta;
     }
-    return index < mMinSizingFunctions.Length() ? mMinSizingFunctions[index]
-                                                : mAutoMinSizing;
-  }
-  const nsStyleCoord& MaxSizingFor(uint32_t aTrackIndex) const {
-    if (MOZ_UNLIKELY(aTrackIndex < mExplicitGridOffset)) {
-      return mAutoMaxSizing;
-    }
-    uint32_t index = aTrackIndex - mExplicitGridOffset;
-    if (index >= mRepeatAutoStart) {
-      if (index < mRepeatAutoEnd) {
-        return mMaxSizingFunctions[mRepeatAutoStart];
-      }
-      index -= mRepeatEndDelta;
-    }
-    return index < mMaxSizingFunctions.Length() ? mMaxSizingFunctions[index]
-                                                : mAutoMaxSizing;
+    return index < mSizingFunctions.Length() ? mSizingFunctions[index]
+                                             : mAutoSizing;
+  }
+  const StyleTrackBreadth& MaxSizingFor(uint32_t aTrackIndex) const {
+    return SizingFor(aTrackIndex).GetMax();
+  }
+  const StyleTrackBreadth& MinSizingFor(uint32_t aTrackIndex) const {
+    return SizingFor(aTrackIndex).GetMin();
   }
   uint32_t NumExplicitTracks() const {
-    return mMinSizingFunctions.Length() + mRepeatEndDelta;
+    return mSizingFunctions.Length() + mRepeatEndDelta;
   }
   uint32_t NumRepeatTracks() const { return mRepeatAutoEnd - mRepeatAutoStart; }
   void SetNumRepeatTracks(uint32_t aNumRepeatTracks) {
     MOZ_ASSERT(mHasRepeatAuto || aNumRepeatTracks == 0);
     mRepeatAutoEnd = mRepeatAutoStart + aNumRepeatTracks;
     mRepeatEndDelta = mHasRepeatAuto ? int32_t(aNumRepeatTracks) - 1 : 0;
   }
 
   // Some style data references, for easy access.
-  const nsTArray<nsStyleCoord>& mMinSizingFunctions;
-  const nsTArray<nsStyleCoord>& mMaxSizingFunctions;
-  const nsStyleCoord& mAutoMinSizing;
-  const nsStyleCoord& mAutoMaxSizing;
+  const nsTArray<StyleTrackSize>& mSizingFunctions;
+  const StyleTrackSize& mAutoSizing;
   // Offset from the start of the implicit grid to the first explicit track.
   uint32_t mExplicitGridOffset;
   // The index of the repeat(auto-fill/fit) track, or zero if there is none.
   // Relative to mExplicitGridOffset (repeat tracks are explicit by definition).
   const uint32_t mRepeatAutoStart;
   // The (hypothetical) index of the last such repeat() track.
   uint32_t mRepeatAutoEnd;
-  // The difference between mExplicitGridEnd and mMinSizingFunctions.Length().
+  // The difference between mExplicitGridEnd and mSizingFunctions.Length().
   int32_t mRepeatEndDelta;
   // True if there is a specified repeat(auto-fill/fit) track.
   const bool mHasRepeatAuto;
   // True if this track (relative to mRepeatAutoStart) is a removed auto-fit.
   // Indexed relative to mExplicitGridOffset + mRepeatAutoStart.
   nsTArray<bool> mRemovedRepeatTracks;
 };
 
@@ -1477,32 +1489,24 @@ struct MOZ_STACK_CLASS
       // range is now in the grand-parent's coordinates
       parentAxis = grandParentAxis;
       parent = grandParent;
     }
     const auto* pos = parent->StylePosition();
     const auto isInlineAxis = parentAxis == eLogicalAxisInline;
     const auto& szf =
         isInlineAxis ? pos->GridTemplateColumns() : pos->GridTemplateRows();
-    const auto& minAuto =
-        isInlineAxis ? pos->mGridAutoColumnsMin : pos->mGridAutoRowsMin;
-    const auto& maxAuto =
-        isInlineAxis ? pos->mGridAutoColumnsMax : pos->mGridAutoRowsMax;
-    TrackSizingFunctions tsf(szf, minAuto, maxAuto);
+    mAutoSizing = isInlineAxis ? &pos->mGridAutoColumns : &pos->mGridAutoRows;
+    TrackSizingFunctions tsf(szf, *mAutoSizing);
     for (auto i : range.Range()) {
-      mMinSizingFunctions.AppendElement(tsf.MinSizingFor(i));
-      mMaxSizingFunctions.AppendElement(tsf.MaxSizingFor(i));
-    }
-    mAutoMinSizing = &minAuto;
-    mAutoMaxSizing = &maxAuto;
-  }
-  nsTArray<nsStyleCoord> mMinSizingFunctions;
-  nsTArray<nsStyleCoord> mMaxSizingFunctions;
-  const nsStyleCoord* mAutoMinSizing;
-  const nsStyleCoord* mAutoMaxSizing;
+      mSizingFunctions.AppendElement(tsf.SizingFor(i));
+    }
+  }
+  nsTArray<StyleTrackSize> mSizingFunctions;
+  const StyleTrackSize* mAutoSizing;
   uint32_t mRepeatAutoIndex = 0;
   bool mHasRepeatAuto = false;
 };
 
 /**
  * State for the tracks in one dimension.
  */
 struct nsGridContainerFrame::Tracks {
@@ -2481,21 +2485,19 @@ struct MOZ_STACK_CLASS nsGridContainerFr
   GridReflowInput(nsGridContainerFrame* aFrame, gfxContext& aRenderingContext,
                   const ReflowInput* aReflowInput,
                   const nsStylePosition* aGridStyle, const WritingMode& aWM)
       : mIter(aFrame, kPrincipalList),
         mGridStyle(aGridStyle),
         mCols(eLogicalAxisInline),
         mRows(eLogicalAxisBlock),
         mColFunctions(mGridStyle->GridTemplateColumns(),
-                      mGridStyle->mGridAutoColumnsMin,
-                      mGridStyle->mGridAutoColumnsMax),
+                      mGridStyle->mGridAutoColumns),
         mRowFunctions(mGridStyle->GridTemplateRows(),
-                      mGridStyle->mGridAutoRowsMin,
-                      mGridStyle->mGridAutoRowsMax),
+                      mGridStyle->mGridAutoRows),
         mReflowInput(aReflowInput),
         mRenderingContext(aRenderingContext),
         mFrame(aFrame),
         mSharedGridData(nullptr),
         mBorderPadding(aWM),
         mFragBStart(0),
         mStartRow(0),
         mNextFragmentStartRow(0),
@@ -3057,40 +3059,36 @@ void nsGridContainerFrame::GridReflowInp
     const auto* parentSizes = parent->GetUsedTrackSizes();
     if (parentSizes && parentSizes->mCanResolveLineRangeSize[parentAxis]) {
       CopyUsedTrackSizes(tracks.mSizes, parent, parentSizes, mFrame, subgrid,
                          aAxis);
       useParentGaps = gapStyle.IsNormal();
     } else {
       fallbackTrackSizing.emplace(mFrame, subgrid, parent, parentAxis);
       tracks.Initialize(
-          TrackSizingFunctions(fallbackTrackSizing->mMinSizingFunctions,
-                               fallbackTrackSizing->mMaxSizingFunctions,
-                               *fallbackTrackSizing->mAutoMinSizing,
-                               *fallbackTrackSizing->mAutoMaxSizing,
+          TrackSizingFunctions(fallbackTrackSizing->mSizingFunctions,
+                               *fallbackTrackSizing->mAutoSizing,
                                fallbackTrackSizing->mHasRepeatAuto,
                                fallbackTrackSizing->mRepeatAutoIndex),
           gapStyle, gridEnd, aContentBoxSize);
     }
   }
 
   // We run the Track Sizing Algorithm in non-subgridded axes, and in some
   // cases in a subgridded axis when our parent track sizes aren't resolved yet.
   if (MOZ_LIKELY(!isSubgriddedAxis) || fallbackTrackSizing.isSome()) {
     const size_t origGridItemCount = mGridItems.Length();
     if (mFrame->HasSubgridItems(aAxis)) {
       CollectSubgridItemsForAxis(aAxis, mGridItems);
     }
     tracks.CalculateSizes(
         *this, mGridItems,
         fallbackTrackSizing.isSome()
-            ? TrackSizingFunctions(fallbackTrackSizing->mMinSizingFunctions,
-                                   fallbackTrackSizing->mMaxSizingFunctions,
-                                   *fallbackTrackSizing->mAutoMinSizing,
-                                   *fallbackTrackSizing->mAutoMaxSizing,
+            ? TrackSizingFunctions(fallbackTrackSizing->mSizingFunctions,
+                                   *fallbackTrackSizing->mAutoSizing,
                                    fallbackTrackSizing->mHasRepeatAuto,
                                    fallbackTrackSizing->mRepeatAutoIndex)
             : sizingFunctions,
         aContentBoxSize,
         aAxis == eLogicalAxisInline ? &GridArea::mCols : &GridArea::mRows,
         aConstraint);
     // XXXmats we're losing the baseline state of subgrid descendants that
     // CollectSubgridItemsForAxis added here.  We need to propagate that
@@ -4320,18 +4318,17 @@ void nsGridContainerFrame::Tracks::Initi
     const NonNegativeLengthPercentageOrNormal& aGridGap, uint32_t aNumTracks,
     nscoord aContentBoxSize) {
   MOZ_ASSERT(aNumTracks >=
              aFunctions.mExplicitGridOffset + aFunctions.NumExplicitTracks());
   mSizes.SetLength(aNumTracks);
   PodZero(mSizes.Elements(), mSizes.Length());
   for (uint32_t i = 0, len = mSizes.Length(); i < len; ++i) {
     mStateUnion |=
-        mSizes[i].Initialize(aContentBoxSize, aFunctions.MinSizingFor(i),
-                             aFunctions.MaxSizingFor(i));
+        mSizes[i].Initialize(aContentBoxSize, aFunctions.SizingFor(i));
   }
   mGridGap = nsLayoutUtils::ResolveGapToLength(aGridGap, aContentBoxSize);
   mContentBoxSize = aContentBoxSize;
 }
 
 /**
  * Reflow aChild in the given aAvailableSize.
  */
@@ -4801,19 +4798,19 @@ bool nsGridContainerFrame::Tracks::Resol
   gfxContext* rc = &aState.mRenderingContext;
   if (sz.mState & TrackSize::eAutoMinSizing) {
     nscoord s;
     // Check if we need to apply "Automatic Minimum Size" and cache it.
     if (aGridItem.ShouldApplyAutoMinSize(wm, mAxis, aPercentageBasis)) {
       aGridItem.mState[mAxis] |= ItemState::eApplyAutoMinSize;
       // Clamp it if it's spanning a definite track max-sizing function.
       if (TrackSize::IsDefiniteMaxSizing(sz.mState)) {
-        auto maxCoord = aFunctions.MaxSizingFor(aRange.mStart);
-        cache.mMinSizeClamp =
-            maxCoord.ComputeCoordPercentCalc(aPercentageBasis);
+        cache.mMinSizeClamp = aFunctions.MaxSizingFor(aRange.mStart)
+                                  .AsBreadth()
+                                  .Resolve(aPercentageBasis);
         aGridItem.mState[mAxis] |= ItemState::eClampMarginBoxMinSize;
       }
       if (aConstraint != SizingConstraint::MaxContent) {
         s = MinContentContribution(aGridItem, aState, rc, wm, mAxis, &cache);
       } else {
         s = MaxContentContribution(aGridItem, aState, rc, wm, mAxis, &cache);
       }
     } else {
@@ -4840,19 +4837,20 @@ bool nsGridContainerFrame::Tracks::Resol
     auto s = MaxContentContribution(aGridItem, aState, rc, wm, mAxis, &cache);
     if (sz.mLimit == NS_UNCONSTRAINEDSIZE) {
       sz.mLimit = s;
     } else {
       sz.mLimit = std::max(sz.mLimit, s);
     }
     if (MOZ_UNLIKELY(sz.mState & TrackSize::eFitContent)) {
       // Clamp mLimit to the fit-content() size, for ยง12.5.1.
-      auto maxCoord = aFunctions.MaxSizingFor(aRange.mStart);
-      nscoord fitContentClamp =
-          maxCoord.ComputeCoordPercentCalc(aPercentageBasis);
+      nscoord fitContentClamp = aFunctions.SizingFor(aRange.mStart)
+                                    .AsFitContent()
+                                    .AsBreadth()
+                                    .Resolve(aPercentageBasis);
       sz.mLimit = std::min(sz.mLimit, fitContentClamp);
     }
   }
   if (sz.mLimit < sz.mBase) {
     sz.mLimit = sz.mBase;
   }
   return sz.mState & TrackSize::eFlexMaxSizing;
 }
@@ -5288,18 +5286,18 @@ void nsGridContainerFrame::Tracks::Resol
         perSpanData[span].mItemCountWithSameSpan++;
         perSpanData[span].mStateBits |= state;
         CachedIntrinsicSizes cache;
         // Calculate data for "Automatic Minimum Size" clamping, if needed.
         if (TrackSize::IsDefiniteMaxSizing(state) &&
             (gridItem.mState[mAxis] & ItemState::eApplyAutoMinSize)) {
           nscoord minSizeClamp = 0;
           for (auto i : lineRange.Range()) {
-            auto maxCoord = aFunctions.MaxSizingFor(i);
-            minSizeClamp += maxCoord.ComputeCoordPercentCalc(aPercentageBasis);
+            minSizeClamp += aFunctions.MaxSizingFor(i).AsBreadth().Resolve(
+                aPercentageBasis);
           }
           minSizeClamp += mGridGap * (span - 1);
           cache.mMinSizeClamp = minSizeClamp;
           gridItem.mState[mAxis] |= ItemState::eClampMarginBoxMinSize;
         }
         // Collect the various grid item size contributions we need.
         nscoord minSize = 0;
         if (state & (TrackSize::eIntrinsicMinSizing |    // for 2.1
@@ -5428,17 +5426,17 @@ float nsGridContainerFrame::Tracks::Find
     const LineRange& aRange, const nsTArray<uint32_t>& aFlexTracks,
     const TrackSizingFunctions& aFunctions, nscoord aSpaceToFill) const {
   MOZ_ASSERT(aSpaceToFill > 0 && !aFlexTracks.IsEmpty());
   float flexFactorSum = 0.0f;
   nscoord leftOverSpace = aSpaceToFill;
   for (auto i : aRange.Range()) {
     const TrackSize& sz = mSizes[i];
     if (sz.mState & TrackSize::eFlexMaxSizing) {
-      flexFactorSum += aFunctions.MaxSizingFor(i).GetFlexFractionValue();
+      flexFactorSum += aFunctions.MaxSizingFor(i).AsFr();
     } else {
       leftOverSpace -= sz.mBase;
       if (leftOverSpace <= 0) {
         return 0.0f;
       }
     }
   }
   bool restart;
@@ -5448,17 +5446,17 @@ float nsGridContainerFrame::Tracks::Find
   do {
     restart = false;
     hypotheticalFrSize = leftOverSpace / std::max(flexFactorSum, 1.0f);
     for (uint32_t i = 0, len = flexTracks.Length(); i < len; ++i) {
       uint32_t track = flexTracks[i];
       if (track == kAutoLine) {
         continue;  // Track marked as inflexible in a prev. iter of this loop.
       }
-      float flexFactor = aFunctions.MaxSizingFor(track).GetFlexFractionValue();
+      float flexFactor = aFunctions.MaxSizingFor(track).AsFr();
       const nscoord base = mSizes[track].mBase;
       if (flexFactor * hypotheticalFrSize < base) {
         // 12.7.1.4: Treat this track as inflexible.
         flexTracks[i] = kAutoLine;
         flexFactorSum -= flexFactor;
         leftOverSpace -= base;
         --numFlexTracks;
         if (numFlexTracks == 0 || leftOverSpace <= 0) {
@@ -5482,17 +5480,17 @@ float nsGridContainerFrame::Tracks::Find
     return FindFrUnitSize(range, aFlexTracks, aFunctions, aAvailableSize);
   }
 
   // The used flex fraction is the maximum of:
   // ... each flexible track's base size divided by its flex factor (which is
   // floored at 1).
   float fr = 0.0f;
   for (uint32_t track : aFlexTracks) {
-    float flexFactor = aFunctions.MaxSizingFor(track).GetFlexFractionValue();
+    float flexFactor = aFunctions.MaxSizingFor(track).AsFr();
     float possiblyDividedBaseSize = (flexFactor > 1.0f)
                                         ? mSizes[track].mBase / flexFactor
                                         : mSizes[track].mBase;
     fr = std::max(fr, possiblyDividedBaseSize);
   }
   WritingMode wm = aState.mWM;
   gfxContext* rc = &aState.mRenderingContext;
   // ... the result of 'finding the size of an fr' for each item that spans
@@ -5557,17 +5555,17 @@ void nsGridContainerFrame::Tracks::Stret
                      aAvailableSize == NS_UNCONSTRAINEDSIZE;
   // We iterate twice at most.  The 2nd time if the grid size changed after
   // applying a min/max-size (can only occur if aAvailableSize is indefinite).
   while (true) {
     float fr = FindUsedFlexFraction(aState, aGridItems, flexTracks, aFunctions,
                                     aAvailableSize);
     if (fr != 0.0f) {
       for (uint32_t i : flexTracks) {
-        float flexFactor = aFunctions.MaxSizingFor(i).GetFlexFractionValue();
+        float flexFactor = aFunctions.MaxSizingFor(i).AsFr();
         nscoord flexLength = NSToCoordRound(flexFactor * fr);
         nscoord& base = mSizes[i].mBase;
         if (flexLength > base) {
           if (applyMinMax && origSizes.isNothing()) {
             origSizes.emplace(mSizes);
           }
           base = flexLength;
         }
--- a/layout/style/GeckoBindings.cpp
+++ b/layout/style/GeckoBindings.cpp
@@ -1265,18 +1265,22 @@ void Gecko_ResizeAtomArray(nsTArray<RefP
 void Gecko_SetStyleGridTemplate(UniquePtr<nsStyleGridTemplate>* aGridTemplate,
                                 nsStyleGridTemplate* aValue) {
   aGridTemplate->reset(aValue);
 }
 
 nsStyleGridTemplate* Gecko_CreateStyleGridTemplate(uint32_t aTrackSizes,
                                                    uint32_t aNameSize) {
   nsStyleGridTemplate* result = new nsStyleGridTemplate;
-  result->mMinTrackSizingFunctions.SetLength(aTrackSizes);
-  result->mMaxTrackSizingFunctions.SetLength(aTrackSizes);
+  result->mTrackSizingFunctions.SetCapacity(aTrackSizes);
+  auto auto_ = StyleTrackSize::Breadth(StyleTrackBreadth::Auto());
+  for (auto i : IntegerRange(aTrackSizes)) {
+    Unused << i;
+    result->mTrackSizingFunctions.AppendElement(auto_);
+  }
   result->mLineNameLists.SetLength(aNameSize);
   return result;
 }
 
 void Gecko_CopyStyleGridTemplateValues(
     UniquePtr<nsStyleGridTemplate>* aGridTemplate,
     const nsStyleGridTemplate* aOther) {
   if (aOther) {
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -511,16 +511,18 @@ cbindgen-types = [
     { gecko = "StyleComputedUrl", servo = "gecko::url::ComputedUrl" },
     { gecko = "StyleComputedImageUrl", servo = "gecko::url::ComputedImageUrl" },
     { gecko = "StyleLoadData", servo = "gecko::url::LoadData" },
     { gecko = "StyleGenericFilter", servo = "values::generics::effects::Filter" },
     { gecko = "StyleGenericGradient", servo = "values::generics::image::Gradient" },
     { gecko = "StyleLineDirection", servo = "values::computed::image::LineDirection" },
     { gecko = "StyleGridTemplateAreas", servo = "values::computed::position::GridTemplateAreas" },
     { gecko = "StyleGenericGridLine", servo = "values::generics::grid::GridLine" },
+    { gecko = "StyleGenericTrackSize", servo = "values::generics::grid::TrackSize" },
+    { gecko = "StyleGenericTrackBreadth", servo = "values::generics::grid::TrackBreadth" },
 ]
 
 mapped-generic-types = [
     { generic = true, gecko = "mozilla::RustCell", servo = "::std::cell::Cell" },
     { generic = false, gecko = "ServoNodeData", servo = "AtomicRefCell<ElementData>" },
     { generic = false, gecko = "mozilla::ServoWritingMode", servo = "::logical_geometry::WritingMode" },
     { generic = false, gecko = "mozilla::ServoCustomPropertiesMap", servo = "Option<::servo_arc::Arc<::custom_properties::CustomPropertiesMap>>" },
     { generic = false, gecko = "mozilla::ServoRuleNode", servo = "Option<::rule_tree::StrongRuleNode>" },
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -1293,77 +1293,112 @@ void nsComputedDOMStyle::AppendGridLineN
     }
     AppendGridLineNames(lineNamesString, aLineNames2);
   }
   lineNamesString.Append(']');
   val->SetString(lineNamesString);
   aValueList->AppendCSSValue(val.forget());
 }
 
-already_AddRefed<CSSValue> nsComputedDOMStyle::GetGridTrackSize(
-    const nsStyleCoord& aMinValue, const nsStyleCoord& aMaxValue) {
-  if (aMinValue.GetUnit() == eStyleUnit_None) {
+void nsComputedDOMStyle::SetValueToTrackBreadth(
+    nsROCSSPrimitiveValue* aValue,
+    const StyleTrackBreadth& aBreadth) {
+  using Tag = StyleTrackBreadth::Tag;
+  switch (aBreadth.tag) {
+    case Tag::MinContent:
+      return aValue->SetIdent(eCSSKeyword_min_content);
+    case Tag::MaxContent:
+      return aValue->SetIdent(eCSSKeyword_max_content);
+    case Tag::Auto:
+      return aValue->SetIdent(eCSSKeyword_auto);
+    case Tag::Breadth:
+      return SetValueToLengthPercentage(aValue, aBreadth.AsBreadth(), true);
+    case Tag::Fr: {
+      nsAutoString tmpStr;
+      nsStyleUtil::AppendCSSNumber(aBreadth.AsFr(), tmpStr);
+      tmpStr.AppendLiteral("fr");
+      return aValue->SetString(tmpStr);
+    }
+    default:
+      MOZ_ASSERT_UNREACHABLE("Unknown breadth value");
+      return;
+  }
+}
+
+already_AddRefed<nsROCSSPrimitiveValue> nsComputedDOMStyle::GetGridTrackBreadth(
+    const StyleTrackBreadth& aBreadth) {
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
+  SetValueToTrackBreadth(val, aBreadth);
+  return val.forget();
+}
+
+already_AddRefed<nsROCSSPrimitiveValue> nsComputedDOMStyle::GetGridTrackSize(
+    const StyleTrackSize& aTrackSize) {
+  if (aTrackSize.IsFitContent()) {
     // A fit-content() function.
     RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     nsAutoString argumentStr, fitContentStr;
     fitContentStr.AppendLiteral("fit-content(");
-    MOZ_ASSERT(aMaxValue.IsCoordPercentCalcUnit(),
+    MOZ_ASSERT(aTrackSize.AsFitContent().IsBreadth(),
                "unexpected unit for fit-content() argument value");
-    SetValueToCoord(val, aMaxValue, true);
+    SetValueToLengthPercentage(val, aTrackSize.AsFitContent().AsBreadth(), true);
     val->GetCssText(argumentStr);
     fitContentStr.Append(argumentStr);
     fitContentStr.Append(char16_t(')'));
     val->SetString(fitContentStr);
     return val.forget();
   }
 
-  if (aMinValue == aMaxValue) {
-    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-    SetValueToCoord(val, aMinValue, true, nullptr,
-                    nsCSSProps::kGridTrackBreadthKTable);
-    return val.forget();
+  if (aTrackSize.IsBreadth()) {
+    return GetGridTrackBreadth(aTrackSize.AsBreadth());
+  }
+
+  MOZ_ASSERT(aTrackSize.IsMinmax());
+  auto& min = aTrackSize.AsMinmax()._0;
+  auto& max = aTrackSize.AsMinmax()._1;
+  if (min == max) {
+    return GetGridTrackBreadth(min);
   }
 
   // minmax(auto, <flex>) is equivalent to (and is our internal representation
   // of) <flex>, and both compute to <flex>
-  if (aMinValue.GetUnit() == eStyleUnit_Auto &&
-      aMaxValue.GetUnit() == eStyleUnit_FlexFraction) {
-    RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-    SetValueToCoord(val, aMaxValue, true);
-    return val.forget();
+  if (min.IsAuto() && max.IsFr()) {
+    return GetGridTrackBreadth(max);
   }
 
-  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   nsAutoString argumentStr, minmaxStr;
   minmaxStr.AppendLiteral("minmax(");
 
-  SetValueToCoord(val, aMinValue, true, nullptr,
-                  nsCSSProps::kGridTrackBreadthKTable);
-  val->GetCssText(argumentStr);
-  minmaxStr.Append(argumentStr);
+  {
+    RefPtr<nsROCSSPrimitiveValue> argValue = GetGridTrackBreadth(min);
+    argValue->GetCssText(argumentStr);
+    minmaxStr.Append(argumentStr);
+    argumentStr.Truncate();
+  }
 
   minmaxStr.AppendLiteral(", ");
 
-  SetValueToCoord(val, aMaxValue, true, nullptr,
-                  nsCSSProps::kGridTrackBreadthKTable);
-  val->GetCssText(argumentStr);
-  minmaxStr.Append(argumentStr);
+  {
+    RefPtr<nsROCSSPrimitiveValue> argValue = GetGridTrackBreadth(max);
+    argValue->GetCssText(argumentStr);
+    minmaxStr.Append(argumentStr);
+  }
 
   minmaxStr.Append(char16_t(')'));
+  RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetString(minmaxStr);
   return val.forget();
 }
 
 already_AddRefed<CSSValue> nsComputedDOMStyle::GetGridTemplateColumnsRows(
     const nsStyleGridTemplate& aTrackList,
     const ComputedGridTrackInfo* aTrackInfo) {
   if (aTrackList.mIsSubgrid) {
     // XXX TODO: add support for repeat(auto-fill) for 'subgrid' (bug 1234311)
-    NS_ASSERTION(aTrackList.mMinTrackSizingFunctions.IsEmpty() &&
-                     aTrackList.mMaxTrackSizingFunctions.IsEmpty(),
+    NS_ASSERTION(aTrackList.mTrackSizingFunctions.IsEmpty(),
                  "Unexpected sizing functions with subgrid");
     RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
     RefPtr<nsROCSSPrimitiveValue> subgridKeyword = new nsROCSSPrimitiveValue;
     subgridKeyword->SetIdent(eCSSKeyword_subgrid);
     valueList->AppendCSSValue(subgridKeyword.forget());
 
     for (uint32_t i = 0, len = aTrackList.mLineNameLists.Length();; ++i) {
@@ -1384,19 +1419,17 @@ already_AddRefed<CSSValue> nsComputedDOM
         break;
       }
       AppendGridLineNames(valueList, aTrackList.mLineNameLists[i],
                           /*aSuppressEmptyList*/ false);
     }
     return valueList.forget();
   }
 
-  uint32_t numSizes = aTrackList.mMinTrackSizingFunctions.Length();
-  MOZ_ASSERT(aTrackList.mMaxTrackSizingFunctions.Length() == numSizes,
-             "Different number of min and max track sizing functions");
+  uint32_t numSizes = aTrackList.mTrackSizingFunctions.Length();
   if (aTrackInfo) {
     DebugOnly<bool> isAutoFill =
         aTrackList.HasRepeatAuto() && aTrackList.mIsAutoFill;
     DebugOnly<bool> isAutoFit =
         aTrackList.HasRepeatAuto() && !aTrackList.mIsAutoFill;
     DebugOnly<uint32_t> numExplicitTracks = aTrackInfo->mNumExplicitTracks;
     MOZ_ASSERT(numExplicitTracks == numSizes ||
                    (isAutoFill && numExplicitTracks >= numSizes) ||
@@ -1557,44 +1590,40 @@ already_AddRefed<CSSValue> nsComputedDOM
                              : NS_LITERAL_STRING("repeat(auto-fit,"));
         valueList->AppendCSSValue(start.forget());
         if (!aTrackList.mRepeatAutoLineNameListBefore.IsEmpty()) {
           AppendGridLineNames(valueList,
                               aTrackList.mRepeatAutoLineNameListBefore);
         }
 
         valueList->AppendCSSValue(
-            GetGridTrackSize(aTrackList.mMinTrackSizingFunctions[i],
-                             aTrackList.mMaxTrackSizingFunctions[i]));
+            GetGridTrackSize(aTrackList.mTrackSizingFunctions[i]));
         if (!aTrackList.mRepeatAutoLineNameListAfter.IsEmpty()) {
           AppendGridLineNames(valueList,
                               aTrackList.mRepeatAutoLineNameListAfter);
         }
         RefPtr<nsROCSSPrimitiveValue> end = new nsROCSSPrimitiveValue;
         end->SetString(NS_LITERAL_STRING(")"));
         valueList->AppendCSSValue(end.forget());
       } else {
         valueList->AppendCSSValue(
-            GetGridTrackSize(aTrackList.mMinTrackSizingFunctions[i],
-                             aTrackList.mMaxTrackSizingFunctions[i]));
+            GetGridTrackSize(aTrackList.mTrackSizingFunctions[i]));
       }
     }
   }
 
   return valueList.forget();
 }
 
 already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetGridAutoColumns() {
-  return GetGridTrackSize(StylePosition()->mGridAutoColumnsMin,
-                          StylePosition()->mGridAutoColumnsMax);
+  return GetGridTrackSize(StylePosition()->mGridAutoColumns);
 }
 
 already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetGridAutoRows() {
-  return GetGridTrackSize(StylePosition()->mGridAutoRowsMin,
-                          StylePosition()->mGridAutoRowsMax);
+  return GetGridTrackSize(StylePosition()->mGridAutoRows);
 }
 
 already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetGridTemplateColumns() {
   const ComputedGridTrackInfo* info = nullptr;
 
   nsGridContainerFrame* gridFrame =
       nsGridContainerFrame::GetGridFrameWithComputedInfo(mInnerFrame);
 
@@ -2311,24 +2340,16 @@ void nsComputedDOMStyle::SetValueToCoord
         SetValueToCalc(calc, aValue);
       }
       break;
 
     case eStyleUnit_Degree:
       aValue->SetDegree(aCoord.GetAngleValue());
       break;
 
-    case eStyleUnit_FlexFraction: {
-      nsAutoString tmpStr;
-      nsStyleUtil::AppendCSSNumber(aCoord.GetFlexFractionValue(), tmpStr);
-      tmpStr.AppendLiteral("fr");
-      aValue->SetString(tmpStr);
-      break;
-    }
-
     default:
       NS_ERROR("Can't handle this unit");
       break;
   }
 }
 
 nscoord nsComputedDOMStyle::StyleCoordToNSCoord(
     const LengthPercentage& aCoord, PercentageBaseGetter aPercentageBaseGetter,
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -196,18 +196,19 @@ class nsComputedDOMStyle final : public 
   // a value ("[]") is only appended if aSuppressEmptyList is false.
   void AppendGridLineNames(nsDOMCSSValueList* aValueList,
                            const nsTArray<RefPtr<nsAtom>>& aLineNames,
                            bool aSuppressEmptyList = true);
   // Appends aLineNames1/2 (if non-empty) as a CSSValue* to aValueList.
   void AppendGridLineNames(nsDOMCSSValueList* aValueList,
                            const nsTArray<RefPtr<nsAtom>>& aLineNames1,
                            const nsTArray<RefPtr<nsAtom>>& aLineNames2);
-  already_AddRefed<CSSValue> GetGridTrackSize(const nsStyleCoord& aMinSize,
-                                              const nsStyleCoord& aMaxSize);
+  already_AddRefed<nsROCSSPrimitiveValue> GetGridTrackSize(const mozilla::StyleTrackSize&);
+  already_AddRefed<nsROCSSPrimitiveValue> GetGridTrackBreadth(const mozilla::StyleTrackBreadth&);
+  void SetValueToTrackBreadth(nsROCSSPrimitiveValue*, const mozilla::StyleTrackBreadth&);
   already_AddRefed<CSSValue> GetGridTemplateColumnsRows(
       const nsStyleGridTemplate& aTrackList,
       const mozilla::ComputedGridTrackInfo* aTrackInfo);
 
   bool GetLineHeightCoord(nscoord& aCoord);
 
   bool ShouldHonorMinSizeAutoInAxis(mozilla::PhysicalAxis aAxis);
 
--- a/layout/style/nsStyleCoord.h
+++ b/layout/style/nsStyleCoord.h
@@ -252,16 +252,21 @@ bool StyleRect<T>::Any(Predicate aPredic
 template <>
 inline const LengthPercentage& BorderRadius::Get(HalfCorner aCorner) const {
   static_assert(sizeof(BorderRadius) == sizeof(LengthPercentage) * 8, "");
   static_assert(alignof(BorderRadius) == alignof(LengthPercentage), "");
   auto* self = reinterpret_cast<const LengthPercentage*>(this);
   return self[aCorner];
 }
 
+template <>
+inline bool StyleTrackBreadth::HasPercent() const {
+  return IsBreadth() && AsBreadth().HasPercent();
+}
+
 }  // namespace mozilla
 
 enum nsStyleUnit : uint8_t {
   eStyleUnit_Null = 0,           // (no value) value is not specified
   eStyleUnit_Normal = 1,         // (no value)
   eStyleUnit_Auto = 2,           // (no value)
   eStyleUnit_None = 3,           // (no value)
   eStyleUnit_Percent = 10,       // (float) 1.0 == 100%
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -1268,20 +1268,18 @@ nsStylePosition::nsStylePosition(const D
       mOffset(StyleRectWithAllSides(LengthPercentageOrAuto::Auto())),
       mWidth(StyleSize::Auto()),
       mMinWidth(StyleSize::Auto()),
       mMaxWidth(StyleMaxSize::None()),
       mHeight(StyleSize::Auto()),
       mMinHeight(StyleSize::Auto()),
       mMaxHeight(StyleMaxSize::None()),
       mFlexBasis(StyleFlexBasis::Size(StyleSize::Auto())),
-      mGridAutoColumnsMin(eStyleUnit_Auto),
-      mGridAutoColumnsMax(eStyleUnit_Auto),
-      mGridAutoRowsMin(eStyleUnit_Auto),
-      mGridAutoRowsMax(eStyleUnit_Auto),
+      mGridAutoColumns(StyleTrackSize::Breadth(StyleTrackBreadth::Auto())),
+      mGridAutoRows(StyleTrackSize::Breadth(StyleTrackBreadth::Auto())),
       mAspectRatio(0.0f),
       mGridAutoFlow(NS_STYLE_GRID_AUTO_FLOW_ROW),
       mBoxSizing(StyleBoxSizing::Content),
       mAlignContent(NS_STYLE_ALIGN_NORMAL),
       mAlignItems(NS_STYLE_ALIGN_NORMAL),
       mAlignSelf(NS_STYLE_ALIGN_AUTO),
       mJustifyContent(NS_STYLE_JUSTIFY_NORMAL),
       mSpecifiedJustifyItems(NS_STYLE_JUSTIFY_LEGACY),
@@ -1315,20 +1313,18 @@ nsStylePosition::nsStylePosition(const n
       mOffset(aSource.mOffset),
       mWidth(aSource.mWidth),
       mMinWidth(aSource.mMinWidth),
       mMaxWidth(aSource.mMaxWidth),
       mHeight(aSource.mHeight),
       mMinHeight(aSource.mMinHeight),
       mMaxHeight(aSource.mMaxHeight),
       mFlexBasis(aSource.mFlexBasis),
-      mGridAutoColumnsMin(aSource.mGridAutoColumnsMin),
-      mGridAutoColumnsMax(aSource.mGridAutoColumnsMax),
-      mGridAutoRowsMin(aSource.mGridAutoRowsMin),
-      mGridAutoRowsMax(aSource.mGridAutoRowsMax),
+      mGridAutoColumns(aSource.mGridAutoColumns),
+      mGridAutoRows(aSource.mGridAutoRows),
       mAspectRatio(aSource.mAspectRatio),
       mGridAutoFlow(aSource.mGridAutoFlow),
       mBoxSizing(aSource.mBoxSizing),
       mAlignContent(aSource.mAlignContent),
       mAlignItems(aSource.mAlignItems),
       mAlignSelf(aSource.mAlignSelf),
       mJustifyContent(aSource.mJustifyContent),
       mSpecifiedJustifyItems(aSource.mSpecifiedJustifyItems),
@@ -1436,20 +1432,18 @@ nsChangeHint nsStylePosition::CalcDiffer
 
   // Properties that apply to grid containers:
   // FIXME: only for grid containers
   // (ie. 'display: grid' or 'display: inline-grid')
   if (!IsGridTemplateEqual(mGridTemplateColumns,
                            aNewData.mGridTemplateColumns) ||
       !IsGridTemplateEqual(mGridTemplateRows, aNewData.mGridTemplateRows) ||
       mGridTemplateAreas != aNewData.mGridTemplateAreas ||
-      mGridAutoColumnsMin != aNewData.mGridAutoColumnsMin ||
-      mGridAutoColumnsMax != aNewData.mGridAutoColumnsMax ||
-      mGridAutoRowsMin != aNewData.mGridAutoRowsMin ||
-      mGridAutoRowsMax != aNewData.mGridAutoRowsMax ||
+      mGridAutoColumns != aNewData.mGridAutoColumns ||
+      mGridAutoRows != aNewData.mGridAutoRows ||
       mGridAutoFlow != aNewData.mGridAutoFlow) {
     return hint | nsChangeHint_AllReflowHints;
   }
 
   // Properties that apply to grid items:
   // FIXME: only for grid items
   // (ie. parent frame is 'display: grid' or 'display: inline-grid')
   if (mGridColumnStart != aNewData.mGridColumnStart ||
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -949,18 +949,17 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
 // (but *not* grid-template-areas.)
 // http://dev.w3.org/csswg/css-grid/#track-sizing
 //
 // This represents either:
 // * none:
 //   mIsSubgrid is false, all three arrays are empty
 // * <track-list>:
 //   mIsSubgrid is false,
-//   mMinTrackSizingFunctions and mMaxTrackSizingFunctions
-//   are of identical non-zero size,
+//   mTrackSizingFunctions is of non-zero size,
 //   and mLineNameLists is one element longer than that.
 //   (Delimiting N columns requires N+1 lines:
 //   one before each track, plus one at the very end.)
 //
 //   An omitted <line-names> is still represented in mLineNameLists,
 //   as an empty sub-array.
 //
 //   A <track-size> specified as a single <track-breadth> is represented
@@ -971,43 +970,41 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
 //   The units for nsStyleCoord are:
 //   * eStyleUnit_Percent represents a <percentage>
 //   * eStyleUnit_FlexFraction represents a <flex> flexible fraction
 //   * eStyleUnit_Coord represents a <length>
 //   * eStyleUnit_Enumerated represents min-content or max-content
 // * subgrid <line-name-list>?:
 //   mIsSubgrid is true,
 //   mLineNameLists may or may not be empty,
-//   mMinTrackSizingFunctions and mMaxTrackSizingFunctions are empty.
+//   mTrackSizingFunctions is empty.
 //
 // If mRepeatAutoIndex != -1 then that index is an <auto-repeat> and
 // mIsAutoFill == true means it's an 'auto-fill', otherwise 'auto-fit'.
 // mRepeatAutoLineNameListBefore is the list of line names before the track
 // size, mRepeatAutoLineNameListAfter the names after.  (They are empty
 // when there is no <auto-repeat> track, i.e. when mRepeatAutoIndex == -1).
 // When mIsSubgrid is true, mRepeatAutoLineNameListBefore contains the line
 // names and mRepeatAutoLineNameListAfter is empty.
 struct nsStyleGridTemplate {
   nsTArray<nsTArray<RefPtr<nsAtom>>> mLineNameLists;
-  nsTArray<nsStyleCoord> mMinTrackSizingFunctions;
-  nsTArray<nsStyleCoord> mMaxTrackSizingFunctions;
+  nsTArray<mozilla::StyleTrackSize> mTrackSizingFunctions;
   nsTArray<RefPtr<nsAtom>> mRepeatAutoLineNameListBefore;
   nsTArray<RefPtr<nsAtom>> mRepeatAutoLineNameListAfter;
   int16_t mRepeatAutoIndex;  // -1 or the track index for an auto-fill/fit track
   bool mIsAutoFill : 1;
   bool mIsSubgrid : 1;
 
   nsStyleGridTemplate()
       : mRepeatAutoIndex(-1), mIsAutoFill(false), mIsSubgrid(false) {}
 
   inline bool operator==(const nsStyleGridTemplate& aOther) const {
     return mIsSubgrid == aOther.mIsSubgrid &&
            mLineNameLists == aOther.mLineNameLists &&
-           mMinTrackSizingFunctions == aOther.mMinTrackSizingFunctions &&
-           mMaxTrackSizingFunctions == aOther.mMaxTrackSizingFunctions &&
+           mTrackSizingFunctions == aOther.mTrackSizingFunctions &&
            mIsAutoFill == aOther.mIsAutoFill &&
            mRepeatAutoIndex == aOther.mRepeatAutoIndex &&
            mRepeatAutoLineNameListBefore ==
                aOther.mRepeatAutoLineNameListBefore &&
            mRepeatAutoLineNameListAfter == aOther.mRepeatAutoLineNameListAfter;
   }
 
   bool HasRepeatAuto() const { return mRepeatAutoIndex != -1; }
@@ -1022,16 +1019,17 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
   using LengthPercentageOrAuto = mozilla::LengthPercentageOrAuto;
   using Position = mozilla::Position;
   template <typename T>
   using StyleRect = mozilla::StyleRect<T>;
   using StyleSize = mozilla::StyleSize;
   using StyleMaxSize = mozilla::StyleMaxSize;
   using StyleFlexBasis = mozilla::StyleFlexBasis;
   using WritingMode = mozilla::WritingMode;
+  using StyleTrackSize = mozilla::StyleTrackSize;
 
   explicit nsStylePosition(const mozilla::dom::Document&);
   nsStylePosition(const nsStylePosition& aOther);
   ~nsStylePosition();
   void TriggerImageLoads(mozilla::dom::Document&, const nsStylePosition*) {}
   const static bool kHasTriggerImageLoads = false;
 
   nsChangeHint CalcDifference(
@@ -1063,20 +1061,18 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
   StyleRect<LengthPercentageOrAuto> mOffset;
   StyleSize mWidth;
   StyleSize mMinWidth;
   StyleMaxSize mMaxWidth;
   StyleSize mHeight;
   StyleSize mMinHeight;
   StyleMaxSize mMaxHeight;
   StyleFlexBasis mFlexBasis;
-  nsStyleCoord mGridAutoColumnsMin;  // coord, percent, enum, calc, flex
-  nsStyleCoord mGridAutoColumnsMax;  // coord, percent, enum, calc, flex
-  nsStyleCoord mGridAutoRowsMin;     // coord, percent, enum, calc, flex
-  nsStyleCoord mGridAutoRowsMax;     // coord, percent, enum, calc, flex
+  StyleTrackSize mGridAutoColumns;
+  StyleTrackSize mGridAutoRows;
   float mAspectRatio;
   uint8_t mGridAutoFlow;             // NS_STYLE_GRID_AUTO_FLOW_*
   mozilla::StyleBoxSizing mBoxSizing;
 
   // All align/justify properties here take NS_STYLE_ALIGN_* values.
   uint16_t mAlignContent;  // fallback value in the high byte
   uint8_t mAlignItems;
   uint8_t mAlignSelf;
--- a/servo/components/style/gecko/conversions.rs
+++ b/servo/components/style/gecko/conversions.rs
@@ -9,24 +9,21 @@
 //! FIXME(emilio): This file should generally just die.
 
 #![allow(unsafe_code)]
 
 use crate::gecko::values::GeckoStyleCoordConvertible;
 use crate::gecko_bindings::bindings;
 use crate::gecko_bindings::structs::{self, nsStyleCoord_CalcValue, Matrix4x4Components};
 use crate::gecko_bindings::structs::{nsStyleImage, nsresult};
-use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
 use crate::stylesheets::RulesMutateError;
 use crate::values::computed::transform::Matrix3D;
 use crate::values::computed::url::ComputedImageUrl;
-use crate::values::computed::{Angle, Gradient, Image};
-use crate::values::computed::{Integer, LengthPercentage};
+use crate::values::computed::{Gradient, Image, LengthPercentage};
 use crate::values::computed::{Length, Percentage, TextAlign};
-use crate::values::generics::grid::{TrackListValue, TrackSize};
 use crate::values::generics::image::GenericImage;
 use crate::values::generics::rect::Rect;
 use crate::Zero;
 use app_units::Au;
 use style_traits::values::specified::AllowedNumericType;
 
 impl From<LengthPercentage> for nsStyleCoord_CalcValue {
     fn from(other: LengthPercentage) -> nsStyleCoord_CalcValue {
@@ -51,21 +48,16 @@ impl From<nsStyleCoord_CalcValue> for Le
         Self::with_clamping_mode(
             Au(other.mLength).into(),
             percentage,
             AllowedNumericType::All,
             /* was_calc = */ true,
         )
     }
 }
-impl From<Angle> for CoordDataValue {
-    fn from(reference: Angle) -> Self {
-        CoordDataValue::Degree(reference.degrees())
-    }
-}
 
 impl nsStyleImage {
     /// Set a given Servo `Image` value into this `nsStyleImage`.
     pub fn set(&mut self, image: Image) {
         match image {
             GenericImage::Gradient(boxed_gradient) => self.set_gradient(boxed_gradient),
             GenericImage::Url(ref url) => unsafe {
                 bindings::Gecko_SetLayerImageImageValue(self, url);
@@ -326,83 +318,16 @@ impl From<RulesMutateError> for nsresult
             RulesMutateError::Syntax => nsresult::NS_ERROR_DOM_SYNTAX_ERR,
             RulesMutateError::IndexSize => nsresult::NS_ERROR_DOM_INDEX_SIZE_ERR,
             RulesMutateError::HierarchyRequest => nsresult::NS_ERROR_DOM_HIERARCHY_REQUEST_ERR,
             RulesMutateError::InvalidState => nsresult::NS_ERROR_DOM_INVALID_STATE_ERR,
         }
     }
 }
 
-impl TrackSize<LengthPercentage> {
-    /// Return TrackSize from given two nsStyleCoord
-    pub fn from_gecko_style_coords<T: CoordData>(gecko_min: &T, gecko_max: &T) -> Self {
-        use crate::gecko_bindings::structs::root::nsStyleUnit;
-        use crate::values::generics::grid::TrackBreadth;
-
-        if gecko_min.unit() == nsStyleUnit::eStyleUnit_None {
-            debug_assert!(
-                gecko_max.unit() == nsStyleUnit::eStyleUnit_Coord ||
-                    gecko_max.unit() == nsStyleUnit::eStyleUnit_Percent ||
-                    gecko_max.unit() == nsStyleUnit::eStyleUnit_Calc
-            );
-            return TrackSize::FitContent(
-                LengthPercentage::from_gecko_style_coord(gecko_max)
-                    .expect("gecko_max could not convert to LengthPercentage"),
-            );
-        }
-
-        let min = TrackBreadth::from_gecko_style_coord(gecko_min)
-            .expect("gecko_min could not convert to TrackBreadth");
-        let max = TrackBreadth::from_gecko_style_coord(gecko_max)
-            .expect("gecko_max could not convert to TrackBreadth");
-        if min == max {
-            TrackSize::Breadth(max)
-        } else {
-            TrackSize::Minmax(min, max)
-        }
-    }
-
-    /// Save TrackSize to given gecko fields.
-    pub fn to_gecko_style_coords<T: CoordDataMut>(&self, gecko_min: &mut T, gecko_max: &mut T) {
-        match *self {
-            TrackSize::FitContent(ref lop) => {
-                // Gecko sets min value to None and max value to the actual value in fit-content
-                // https://searchfox.org/mozilla-central/rev/c05d9d61188d32b8/layout/style/nsRuleNode.cpp#7910
-                gecko_min.set_value(CoordDataValue::None);
-                lop.to_gecko_style_coord(gecko_max);
-            },
-            TrackSize::Breadth(ref breadth) => {
-                // Set the value to both fields if there's one breadth value
-                // https://searchfox.org/mozilla-central/rev/c05d9d61188d32b8/layout/style/nsRuleNode.cpp#7919
-                breadth.to_gecko_style_coord(gecko_min);
-                breadth.to_gecko_style_coord(gecko_max);
-            },
-            TrackSize::Minmax(ref min, ref max) => {
-                min.to_gecko_style_coord(gecko_min);
-                max.to_gecko_style_coord(gecko_max);
-            },
-        }
-    }
-}
-
-impl TrackListValue<LengthPercentage, Integer> {
-    /// Return TrackSize from given two nsStyleCoord
-    pub fn from_gecko_style_coords<T: CoordData>(gecko_min: &T, gecko_max: &T) -> Self {
-        TrackListValue::TrackSize(TrackSize::from_gecko_style_coords(gecko_min, gecko_max))
-    }
-
-    /// Save TrackSize to given gecko fields.
-    pub fn to_gecko_style_coords<T: CoordDataMut>(&self, gecko_min: &mut T, gecko_max: &mut T) {
-        match *self {
-            TrackListValue::TrackSize(ref size) => size.to_gecko_style_coords(gecko_min, gecko_max),
-            _ => unreachable!("Should only transform from track-size computed values"),
-        }
-    }
-}
-
 impl<T> Rect<T>
 where
     T: GeckoStyleCoordConvertible,
 {
     /// Convert this generic Rect to given Gecko fields.
     pub fn to_gecko_rect(&self, sides: &mut crate::gecko_bindings::structs::nsStyleSides) {
         self.0.to_gecko_style_coord(&mut sides.data_at_mut(0));
         self.1.to_gecko_style_coord(&mut sides.data_at_mut(1));
--- a/servo/components/style/gecko/values.rs
+++ b/servo/components/style/gecko/values.rs
@@ -2,22 +2,20 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
 
 #![allow(unsafe_code)]
 
 //! Different kind of helpers to interact with Gecko values.
 
 use crate::counter_style::{Symbol, Symbols};
-use crate::gecko_bindings::structs::StyleGridTrackBreadth;
 use crate::gecko_bindings::structs::{nsStyleCoord, CounterStylePtr};
 use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
-use crate::values::computed::{Angle, Length, LengthPercentage};
+use crate::values::computed::{Length, LengthPercentage};
 use crate::values::computed::{Number, NumberOrPercentage, Percentage};
-use crate::values::generics::grid::{TrackBreadth, TrackKeyword};
 use crate::values::generics::length::LengthPercentageOrAuto;
 use crate::values::generics::{CounterStyleOrNone, NonNegative};
 use crate::values::Either;
 use crate::{Atom, Zero};
 use app_units::Au;
 use cssparser::RGBA;
 use nsstring::{nsACString, nsCStr};
 use std::cmp::max;
@@ -149,78 +147,30 @@ where
         match coord.as_value() {
             CoordDataValue::Auto => Some(LengthPercentageOrAuto::Auto),
             _ => LengthPercentage::from_gecko_style_coord(coord)
                 .map(LengthPercentageOrAuto::LengthPercentage),
         }
     }
 }
 
-impl<L: GeckoStyleCoordConvertible> GeckoStyleCoordConvertible for TrackBreadth<L> {
-    fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
-        match *self {
-            TrackBreadth::Breadth(ref lp) => lp.to_gecko_style_coord(coord),
-            TrackBreadth::Fr(fr) => coord.set_value(CoordDataValue::FlexFraction(fr)),
-            TrackBreadth::Keyword(TrackKeyword::Auto) => coord.set_value(CoordDataValue::Auto),
-            TrackBreadth::Keyword(TrackKeyword::MinContent) => coord.set_value(
-                CoordDataValue::Enumerated(StyleGridTrackBreadth::MinContent as u32),
-            ),
-            TrackBreadth::Keyword(TrackKeyword::MaxContent) => coord.set_value(
-                CoordDataValue::Enumerated(StyleGridTrackBreadth::MaxContent as u32),
-            ),
-        }
-    }
-
-    fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
-        L::from_gecko_style_coord(coord)
-            .map(TrackBreadth::Breadth)
-            .or_else(|| match coord.as_value() {
-                CoordDataValue::Enumerated(v) => {
-                    if v == StyleGridTrackBreadth::MinContent as u32 {
-                        Some(TrackBreadth::Keyword(TrackKeyword::MinContent))
-                    } else if v == StyleGridTrackBreadth::MaxContent as u32 {
-                        Some(TrackBreadth::Keyword(TrackKeyword::MaxContent))
-                    } else {
-                        None
-                    }
-                },
-                CoordDataValue::FlexFraction(fr) => Some(TrackBreadth::Fr(fr)),
-                CoordDataValue::Auto => Some(TrackBreadth::Keyword(TrackKeyword::Auto)),
-                _ => L::from_gecko_style_coord(coord).map(TrackBreadth::Breadth),
-            })
-    }
-}
-
 impl<T: GeckoStyleCoordConvertible> GeckoStyleCoordConvertible for Option<T> {
     fn to_gecko_style_coord<U: CoordDataMut>(&self, coord: &mut U) {
         if let Some(ref me) = *self {
             me.to_gecko_style_coord(coord);
         } else {
             coord.set_value(CoordDataValue::None);
         }
     }
 
     fn from_gecko_style_coord<U: CoordData>(coord: &U) -> Option<Self> {
         Some(T::from_gecko_style_coord(coord))
     }
 }
 
-impl GeckoStyleCoordConvertible for Angle {
-    fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
-        coord.set_value(CoordDataValue::from(*self));
-    }
-
-    fn from_gecko_style_coord<T: CoordData>(coord: &T) -> Option<Self> {
-        match coord.as_value() {
-            CoordDataValue::Degree(val) => Some(Angle::from_degrees(val)),
-            _ => None,
-        }
-    }
-}
-
 /// Convert a given RGBA value to `nscolor`.
 pub fn convert_rgba_to_nscolor(rgba: &RGBA) -> u32 {
     ((rgba.alpha as u32) << 24) |
         ((rgba.blue as u32) << 16) |
         ((rgba.green as u32) << 8) |
         (rgba.red as u32)
 }
 
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -31,17 +31,16 @@ use crate::gecko_bindings::bindings::Gec
 use crate::gecko_bindings::bindings::Gecko_nsStyleFont_SetLang;
 use crate::gecko_bindings::bindings::Gecko_nsStyleFont_CopyLangFrom;
 use crate::gecko_bindings::bindings::Gecko_SetListStyleImageNone;
 use crate::gecko_bindings::bindings::Gecko_SetListStyleImageImageValue;
 use crate::gecko_bindings::bindings::Gecko_SetNullImageValue;
 use crate::gecko_bindings::structs;
 use crate::gecko_bindings::structs::nsCSSPropertyID;
 use crate::gecko_bindings::structs::mozilla::PseudoStyleType;
-use crate::gecko_bindings::sugar::ns_style_coord::CoordDataMut;
 use crate::gecko_bindings::sugar::refptr::RefPtr;
 use crate::gecko::values::round_border_to_device_pixels;
 use crate::logical_geometry::WritingMode;
 use crate::media_queries::Device;
 use crate::properties::computed_value_flags::*;
 use crate::properties::longhands;
 use crate::rule_tree::StrongRuleNode;
 use crate::selector_parser::PseudoElement;
@@ -1070,17 +1069,16 @@ fn static_assert() {
     % endfor
 </%self:impl_trait>
 
 <% skip_position_longhands = " ".join(x.ident for x in SIDES) %>
 <%self:impl_trait style_struct_name="Position"
                   skip_longhands="${skip_position_longhands} order
                                   align-content justify-content align-self
                                   justify-self align-items justify-items
-                                  grid-auto-rows grid-auto-columns
                                   grid-auto-flow grid-template-rows
                                   grid-template-columns">
     % for side in SIDES:
     <% impl_split_style_coord(side.ident, "mOffset", side.index) %>
     % endfor
 
     % for kind in ["align", "justify"]:
     ${impl_simple_type_with_conversion(kind + "_content")}
@@ -1121,43 +1119,23 @@ fn static_assert() {
 
     pub fn clone_order(&self) -> longhands::order::computed_value::T {
         self.gecko.mOrder
     }
 
     ${impl_simple_copy('order', 'mOrder')}
 
     % for kind in ["rows", "columns"]:
-    pub fn set_grid_auto_${kind}(&mut self, v: longhands::grid_auto_${kind}::computed_value::T) {
-        let gecko = &mut *self.gecko;
-        v.to_gecko_style_coords(&mut gecko.mGridAuto${kind.title()}Min,
-                                &mut gecko.mGridAuto${kind.title()}Max)
-    }
-
-    pub fn copy_grid_auto_${kind}_from(&mut self, other: &Self) {
-        self.gecko.mGridAuto${kind.title()}Min.copy_from(&other.gecko.mGridAuto${kind.title()}Min);
-        self.gecko.mGridAuto${kind.title()}Max.copy_from(&other.gecko.mGridAuto${kind.title()}Max);
-    }
-
-    pub fn reset_grid_auto_${kind}(&mut self, other: &Self) {
-        self.copy_grid_auto_${kind}_from(other)
-    }
-
-    pub fn clone_grid_auto_${kind}(&self) -> longhands::grid_auto_${kind}::computed_value::T {
-        crate::values::generics::grid::TrackSize::from_gecko_style_coords(&self.gecko.mGridAuto${kind.title()}Min,
-                                                                     &self.gecko.mGridAuto${kind.title()}Max)
-    }
-
     pub fn set_grid_template_${kind}(&mut self, v: longhands::grid_template_${kind}::computed_value::T) {
         <% self_grid = "self.gecko.mGridTemplate%s" % kind.title() %>
         use crate::gecko_bindings::structs::nsTArray;
         use std::usize;
         use crate::values::CustomIdent;
         use crate::values::generics::grid::TrackListType::Auto;
-        use crate::values::generics::grid::{GridTemplateComponent, RepeatCount, MAX_GRID_LINE};
+        use crate::values::generics::grid::{GridTemplateComponent, RepeatCount, TrackListValue, MAX_GRID_LINE};
 
         #[inline]
         fn set_line_names(servo_names: &[CustomIdent], gecko_names: &mut nsTArray<structs::RefPtr<structs::nsAtom>>) {
             unsafe {
                 bindings::Gecko_ResizeAtomArray(gecko_names, servo_names.len() as u32);
             }
 
             for (servo_name, gecko_name) in servo_names.iter().zip(gecko_names.iter_mut()) {
@@ -1206,30 +1184,29 @@ fn static_assert() {
                         bindings::Gecko_ResizeAtomArray(
                             &mut value.mRepeatAutoLineNameListAfter, 0);
                     }
                 }
 
                 let mut line_names = track.line_names.into_iter();
                 let mut values_iter = track.values.into_iter();
                 {
-                    let min_max_iter = value.mMinTrackSizingFunctions.iter_mut()
-                                            .zip(value.mMaxTrackSizingFunctions.iter_mut());
-                    for (i, (gecko_min, gecko_max)) in min_max_iter.enumerate().take(max_lines) {
+                    for (i, track_size) in value.mTrackSizingFunctions.iter_mut().enumerate().take(max_lines) {
                         let name_list = line_names.next().expect("expected line-names");
                         set_line_names(&name_list, &mut value.mLineNameLists[i]);
-                        if i == auto_idx {
-                            let track_size = auto_track_size.take()
-                                .expect("expected <track-size> for <auto-track-repeat>");
-                            track_size.to_gecko_style_coords(gecko_min, gecko_max);
-                            continue
-                        }
-
-                        let track_size = values_iter.next().expect("expected <track-size> value");
-                        track_size.to_gecko_style_coords(gecko_min, gecko_max);
+                        *track_size = if i == auto_idx {
+                            auto_track_size.take().expect("expected <track-size> for <auto-track-repeat>")
+                        } else {
+                            match values_iter.next().expect("expected <track-size> value") {
+                                TrackListValue::TrackSize(size) => size,
+                                // FIXME(emilio): This shouldn't be
+                                // representable in the first place.
+                                TrackListValue::TrackRepeat(..) => unreachable!("Shouldn't have track-repeats in computed track lists"),
+                            }
+                        };
                     }
                 }
 
                 let final_names = line_names.next().unwrap();
                 set_line_names(&final_names, value.mLineNameLists.last_mut().unwrap());
 
                 value
             },
@@ -1274,17 +1251,17 @@ fn static_assert() {
         self.copy_grid_template_${kind}_from(other)
     }
 
     pub fn clone_grid_template_${kind}(&self) -> longhands::grid_template_${kind}::computed_value::T {
         <% self_grid = "self.gecko.mGridTemplate%s" % kind.title() %>
         use crate::gecko_bindings::structs::nsTArray;
         use crate::values::CustomIdent;
         use crate::values::generics::grid::{GridTemplateComponent, LineNameList, RepeatCount};
-        use crate::values::generics::grid::{TrackList, TrackListType, TrackListValue, TrackRepeat, TrackSize};
+        use crate::values::generics::grid::{TrackList, TrackListType, TrackListValue, TrackRepeat};
 
         let value = match unsafe { ${self_grid}.mPtr.as_ref() } {
             None => return GridTemplateComponent::None,
             Some(value) => value,
         };
 
         #[inline]
         fn to_boxed_customident_slice(gecko_names: &nsTArray<structs::RefPtr<structs::nsAtom>>) -> Box<[CustomIdent]> {
@@ -1316,23 +1293,18 @@ fn static_assert() {
             };
             let names = names_vec.into_boxed_slice();
 
             GridTemplateComponent::Subgrid(LineNameList{names, fill_idx})
         } else {
             let mut auto_repeat = None;
             let mut list_type = TrackListType::Normal;
             let line_names = to_line_names_vec(&value.mLineNameLists).into_boxed_slice();
-            let mut values = Vec::with_capacity(value.mMinTrackSizingFunctions.len());
-
-            let min_max_iter = value.mMinTrackSizingFunctions.iter()
-                .zip(value.mMaxTrackSizingFunctions.iter());
-            for (i, (gecko_min, gecko_max)) in min_max_iter.enumerate() {
-                let track_size = TrackSize::from_gecko_style_coords(gecko_min, gecko_max);
-
+            let mut values = Vec::with_capacity(value.mTrackSizingFunctions.len());
+            for (i, track_size) in value.mTrackSizingFunctions.iter().enumerate() {
                 if i == repeat_auto_index {
                     list_type = TrackListType::Auto(repeat_auto_index as u16);
 
                     let count = if value.mIsAutoFill() {
                         RepeatCount::AutoFill
                     } else {
                         RepeatCount::AutoFit
                     };
@@ -1341,21 +1313,21 @@ fn static_assert() {
                         let mut vec: Vec<Box<[CustomIdent]>> = Vec::with_capacity(2);
                         vec.push(to_boxed_customident_slice(
                             &value.mRepeatAutoLineNameListBefore));
                         vec.push(to_boxed_customident_slice(
                             &value.mRepeatAutoLineNameListAfter));
                         vec.into_boxed_slice()
                     };
 
-                    let track_sizes = vec!(track_size);
+                    let track_sizes = vec!(track_size.clone());
 
                     auto_repeat = Some(TrackRepeat{count, line_names, track_sizes});
                 } else {
-                    values.push(TrackListValue::TrackSize(track_size));
+                    values.push(TrackListValue::TrackSize(track_size.clone()));
                 }
             }
 
             GridTemplateComponent::TrackList(TrackList{list_type, values, line_names, auto_repeat})
         }
     }
     % endfor
 
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -2,18 +2,18 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
 
 //! Computed values.
 
 use self::transform::DirectionVector;
 use super::animated::ToAnimatedValue;
 use super::generics::grid::GridTemplateComponent as GenericGridTemplateComponent;
-use super::generics::grid::{GenericGridLine, TrackBreadth as GenericTrackBreadth};
-use super::generics::grid::{TrackList as GenericTrackList, TrackSize as GenericTrackSize};
+use super::generics::grid::{GenericGridLine, GenericTrackBreadth};
+use super::generics::grid::{TrackList as GenericTrackList, GenericTrackSize};
 use super::generics::transform::IsParallelTo;
 use super::generics::{self, GreaterThanOrEqualToOne, NonNegative, ZeroToOne};
 use super::specified;
 use super::{CSSFloat, CSSInteger};
 use crate::context::QuirksMode;
 use crate::font_metrics::{get_metrics_provider_for_product, FontMetricsProvider};
 use crate::media_queries::Device;
 #[cfg(feature = "gecko")]
--- a/servo/components/style/values/generics/grid.rs
+++ b/servo/components/style/values/generics/grid.rs
@@ -2,17 +2,16 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
 
 //! Generic types for the handling of
 //! [grids](https://drafts.csswg.org/css-grid/).
 
 use crate::{Atom, Zero};
 use crate::parser::{Parse, ParserContext};
-use crate::values::computed::{Context, ToComputedValue};
 use crate::values::specified;
 use crate::values::specified::grid::parse_line_names;
 use crate::values::{CSSFloat, CustomIdent};
 use cssparser::Parser;
 use std::fmt::{self, Write};
 use std::{cmp, mem, usize};
 use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
 
@@ -175,96 +174,90 @@ impl Parse for GridLine<specified::Integ
                 return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
             }
         }
 
         Ok(grid_line)
     }
 }
 
-#[allow(missing_docs)]
-#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
-#[derive(
-    Animate,
-    Clone,
-    Copy,
-    Debug,
-    Eq,
-    MallocSizeOf,
-    Parse,
-    PartialEq,
-    SpecifiedValueInfo,
-    ToComputedValue,
-    ToCss,
-    ToResolvedValue,
-    ToShmem,
-)]
-pub enum TrackKeyword {
-    Auto,
-    MaxContent,
-    MinContent,
-}
-
 /// A track breadth for explicit grid track sizing. It's generic solely to
 /// avoid re-implementing it for the computed type.
 ///
 /// <https://drafts.csswg.org/css-grid/#typedef-track-breadth>
+///
+/// cbindgen:derive-tagged-enum-copy-constructor=true
 #[derive(
     Animate,
     Clone,
     Debug,
     MallocSizeOf,
     PartialEq,
     SpecifiedValueInfo,
     ToComputedValue,
     ToCss,
     ToResolvedValue,
     ToShmem,
 )]
-pub enum TrackBreadth<L> {
+#[repr(C, u8)]
+pub enum GenericTrackBreadth<L> {
     /// The generic type is almost always a non-negative `<length-percentage>`
     Breadth(L),
     /// A flex fraction specified in `fr` units.
     #[css(dimension)]
     Fr(CSSFloat),
-    /// One of the track-sizing keywords (`auto`, `min-content`, `max-content`)
-    Keyword(TrackKeyword),
+    /// `auto`
+    Auto,
+    /// `min-content`
+    MinContent,
+    /// `max-content`
+    MaxContent,
 }
 
+pub use self::GenericTrackBreadth as TrackBreadth;
+
 impl<L> TrackBreadth<L> {
     /// Check whether this is a `<fixed-breadth>` (i.e., it only has `<length-percentage>`)
     ///
     /// <https://drafts.csswg.org/css-grid/#typedef-fixed-breadth>
     #[inline]
     pub fn is_fixed(&self) -> bool {
         matches!(*self, TrackBreadth::Breadth(..))
     }
 }
 
 /// A `<track-size>` type for explicit grid track sizing. Like `<track-breadth>`, this is
 /// generic only to avoid code bloat. It only takes `<length-percentage>`
 ///
 /// <https://drafts.csswg.org/css-grid/#typedef-track-size>
-#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToResolvedValue, ToShmem)]
-pub enum TrackSize<L> {
+///
+/// cbindgen:derive-tagged-enum-copy-constructor=true
+#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem)]
+#[repr(C, u8)]
+pub enum GenericTrackSize<L> {
     /// A flexible `<track-breadth>`
-    Breadth(TrackBreadth<L>),
+    Breadth(GenericTrackBreadth<L>),
     /// A `minmax` function for a range over an inflexible `<track-breadth>`
     /// and a flexible `<track-breadth>`
     ///
     /// <https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-minmax>
     #[css(function)]
-    Minmax(TrackBreadth<L>, TrackBreadth<L>),
+    Minmax(GenericTrackBreadth<L>, GenericTrackBreadth<L>),
     /// A `fit-content` function.
     ///
+    /// This stores a TrackBreadth<L> for convenience, but it can only be a
+    /// LengthPercentage.
+    ///
     /// <https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-fit-content>
     #[css(function)]
-    FitContent(L),
+    FitContent(GenericTrackBreadth<L>),
 }
 
+pub use self::GenericTrackSize as TrackSize;
+
 impl<L> TrackSize<L> {
     /// Check whether this is a `<fixed-size>`
     ///
     /// <https://drafts.csswg.org/css-grid/#typedef-fixed-size>
     pub fn is_fixed(&self) -> bool {
         match *self {
             TrackSize::Breadth(ref breadth) => breadth.is_fixed(),
             // For minmax function, it could be either
@@ -283,17 +276,17 @@ impl<L> TrackSize<L> {
             },
             TrackSize::FitContent(_) => false,
         }
     }
 }
 
 impl<L> Default for TrackSize<L> {
     fn default() -> Self {
-        TrackSize::Breadth(TrackBreadth::Keyword(TrackKeyword::Auto))
+        TrackSize::Breadth(TrackBreadth::Auto)
     }
 }
 
 impl<L: PartialEq> TrackSize<L> {
     /// Returns true if current TrackSize is same as default.
     pub fn is_default(&self) -> bool {
         *self == TrackSize::default()
     }
@@ -304,17 +297,17 @@ impl<L: ToCss> ToCss for TrackSize<L> {
     where
         W: Write,
     {
         match *self {
             TrackSize::Breadth(ref breadth) => breadth.to_css(dest),
             TrackSize::Minmax(ref min, ref max) => {
                 // According to gecko minmax(auto, <flex>) is equivalent to <flex>,
                 // and both are serialized as <flex>.
-                if let TrackBreadth::Keyword(TrackKeyword::Auto) = *min {
+                if let TrackBreadth::Auto = *min {
                     if let TrackBreadth::Fr(_) = *max {
                         return max.to_css(dest);
                     }
                 }
 
                 dest.write_str("minmax(")?;
                 min.to_css(dest)?;
                 dest.write_str(", ")?;
@@ -325,58 +318,16 @@ impl<L: ToCss> ToCss for TrackSize<L> {
                 dest.write_str("fit-content(")?;
                 lp.to_css(dest)?;
                 dest.write_str(")")
             },
         }
     }
 }
 
-impl<L: ToComputedValue> ToComputedValue for TrackSize<L> {
-    type ComputedValue = TrackSize<L::ComputedValue>;
-
-    #[inline]
-    fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
-        match *self {
-            TrackSize::Breadth(TrackBreadth::Fr(ref f)) => {
-                // <flex> outside `minmax()` expands to `mimmax(auto, <flex>)`
-                // https://drafts.csswg.org/css-grid/#valdef-grid-template-columns-flex
-                // FIXME(nox): This sounds false, the spec just says that <flex>
-                // implies `minmax(auto, <flex>)`, not that it should be changed
-                // into `minmax` at computed value time.
-                TrackSize::Minmax(
-                    TrackBreadth::Keyword(TrackKeyword::Auto),
-                    TrackBreadth::Fr(f.to_computed_value(context)),
-                )
-            },
-            TrackSize::Breadth(ref b) => TrackSize::Breadth(b.to_computed_value(context)),
-            TrackSize::Minmax(ref b1, ref b2) => {
-                TrackSize::Minmax(b1.to_computed_value(context), b2.to_computed_value(context))
-            },
-            TrackSize::FitContent(ref lp) => TrackSize::FitContent(lp.to_computed_value(context)),
-        }
-    }
-
-    #[inline]
-    fn from_computed_value(computed: &Self::ComputedValue) -> Self {
-        match *computed {
-            TrackSize::Breadth(ref b) => {
-                TrackSize::Breadth(ToComputedValue::from_computed_value(b))
-            },
-            TrackSize::Minmax(ref b1, ref b2) => TrackSize::Minmax(
-                ToComputedValue::from_computed_value(b1),
-                ToComputedValue::from_computed_value(b2),
-            ),
-            TrackSize::FitContent(ref lp) => {
-                TrackSize::FitContent(ToComputedValue::from_computed_value(lp))
-            },
-        }
-    }
-}
-
 /// Helper function for serializing identifiers with a prefix and suffix, used
 /// for serializing <line-names> (in grid).
 pub fn concat_serialize_idents<W>(
     prefix: &str,
     suffix: &str,
     slice: &[CustomIdent],
     sep: &str,
     dest: &mut CssWriter<W>,
--- a/servo/components/style/values/specified/grid.rs
+++ b/servo/components/style/values/specified/grid.rs
@@ -3,17 +3,17 @@
  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
 
 //! CSS handling for the computed value of
 //! [grids](https://drafts.csswg.org/css-grid/)
 
 use crate::parser::{Parse, ParserContext};
 use crate::values::computed::{self, Context, ToComputedValue};
 use crate::values::generics::grid::{GridTemplateComponent, RepeatCount, TrackBreadth};
-use crate::values::generics::grid::{LineNameList, TrackKeyword, TrackRepeat, TrackSize};
+use crate::values::generics::grid::{LineNameList, TrackRepeat, TrackSize};
 use crate::values::generics::grid::{TrackList, TrackListType, TrackListValue};
 use crate::values::specified::{Integer, LengthPercentage};
 use crate::values::{CSSFloat, CustomIdent};
 use cssparser::{ParseError as CssParseError, Parser, Token};
 use std::mem;
 use style_traits::{ParseError, StyleParseErrorKind};
 
 /// Parse a single flexible length.
@@ -22,30 +22,53 @@ pub fn parse_flex<'i, 't>(input: &mut Pa
     match *input.next()? {
         Token::Dimension {
             value, ref unit, ..
         } if unit.eq_ignore_ascii_case("fr") && value.is_sign_positive() => Ok(value),
         ref t => Err(location.new_unexpected_token_error(t.clone())),
     }
 }
 
+impl<L> TrackBreadth<L> {
+    fn parse_keyword<'i, 't>(
+        input: &mut Parser<'i, 't>,
+    ) -> Result<Self, ParseError<'i>> {
+        #[derive(Parse)]
+        enum TrackKeyword {
+            Auto,
+            MaxContent,
+            MinContent,
+        }
+
+        Ok(match TrackKeyword::parse(input)? {
+            TrackKeyword::Auto => TrackBreadth::Auto,
+            TrackKeyword::MaxContent => TrackBreadth::MaxContent,
+            TrackKeyword::MinContent => TrackBreadth::MinContent,
+        })
+    }
+}
+
 impl Parse for TrackBreadth<LengthPercentage> {
     fn parse<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
     ) -> Result<Self, ParseError<'i>> {
+        // FIXME: This and other callers in this file should use
+        // NonNegativeLengthPercentage instead.
+        //
+        // Though it seems these cannot be animated so it's ~ok.
         if let Ok(lp) = input.try(|i| LengthPercentage::parse_non_negative(context, i)) {
             return Ok(TrackBreadth::Breadth(lp));
         }
 
         if let Ok(f) = input.try(parse_flex) {
             return Ok(TrackBreadth::Fr(f));
         }
 
-        TrackKeyword::parse(input).map(TrackBreadth::Keyword)
+        Self::parse_keyword(input)
     }
 }
 
 impl Parse for TrackSize<LengthPercentage> {
     fn parse<'i, 't>(
         context: &ParserContext,
         input: &mut Parser<'i, 't>,
     ) -> Result<Self, ParseError<'i>> {
@@ -53,33 +76,30 @@ impl Parse for TrackSize<LengthPercentag
             return Ok(TrackSize::Breadth(b));
         }
 
         if input.try(|i| i.expect_function_matching("minmax")).is_ok() {
             return input.parse_nested_block(|input| {
                 let inflexible_breadth =
                     match input.try(|i| LengthPercentage::parse_non_negative(context, i)) {
                         Ok(lp) => TrackBreadth::Breadth(lp),
-                        Err(..) => {
-                            let keyword = TrackKeyword::parse(input)?;
-                            TrackBreadth::Keyword(keyword)
-                        },
+                        Err(..) => TrackBreadth::parse_keyword(input)?,
                     };
 
                 input.expect_comma()?;
                 Ok(TrackSize::Minmax(
                     inflexible_breadth,
                     TrackBreadth::parse(context, input)?,
                 ))
             });
         }
 
         input.expect_function_matching("fit-content")?;
         let lp = input.parse_nested_block(|i| LengthPercentage::parse_non_negative(context, i))?;
-        Ok(TrackSize::FitContent(lp))
+        Ok(TrackSize::FitContent(TrackBreadth::Breadth(lp)))
     }
 }
 
 /// Parse the grid line names into a vector of owned strings.
 ///
 /// <https://drafts.csswg.org/css-grid/#typedef-line-names>
 pub fn parse_line_names<'i, 't>(
     input: &mut Parser<'i, 't>,
--- a/servo/ports/geckolib/cbindgen.toml
+++ b/servo/ports/geckolib/cbindgen.toml
@@ -153,16 +153,18 @@ include = [
   "BorderImageWidth",
   "ComputedUrl",
   "ComputedImageUrl",
   "UrlOrNone",
   "Filter",
   "Gradient",
   "GridTemplateAreas",
   "GridLine",
+  "TrackSize",
+  "TrackBreadth",
 ]
 item_types = ["enums", "structs", "typedefs", "functions", "constants"]
 renaming_overrides_prefixing = true
 
 # Prevent some renaming for Gecko types that cbindgen doesn't otherwise understand.
 [export.rename]
 "nscolor" = "nscolor"
 "nsAtom" = "nsAtom"
@@ -602,8 +604,29 @@ renaming_overrides_prefixing = true
 
 "GenericGridLine" = """
   // Returns the `auto` value.
   inline StyleGenericGridLine();
   inline bool IsAuto() const;
   // The line name, or nsGkAtoms::_empty if not present.
   inline nsAtom* LineName() const;
 """
+
+"GenericTrackBreadth" = """
+ private:
+  // Private default constructor without initialization so that the helper
+  // constructor functions still work as expected. They take care of
+  // initializing the fields properly.
+  StyleGenericTrackBreadth() {}
+ public:
+  inline bool HasPercent() const;
+"""
+
+"GenericTrackSize" = """
+ private:
+  // Private default constructor without initialization so that the helper
+  // constructor functions still work as expected. They take care of
+  // initializing the fields properly.
+  StyleGenericTrackSize() {}
+ public:
+  inline const StyleGenericTrackBreadth<L>& GetMin() const;
+  inline const StyleGenericTrackBreadth<L>& GetMax() const;
+"""