Backed out 3 changesets (bug 1541546) for causing build bustages. CLOSED TREE
authorCosmin Sabou <csabou@mozilla.com>
Thu, 04 Apr 2019 15:04:25 +0300
changeset 467982 95484a7dc30b364232a5cc905bdfdf4f665d369b
parent 467981 a7b2c2564ead4c7e029270b71b2b74c93576707c
child 467983 28eb8a6b33f63322188eb1ca0e4bcb3b3fb43432
push id112667
push useraiakab@mozilla.com
push dateThu, 04 Apr 2019 16:12:45 +0000
treeherdermozilla-inbound@230bb363f2f3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1541546
milestone68.0a1
backs out895863144707dd9216fcb26807a22217a5e3eda1
4da6fb98e8f9d7db99181e763919a765f0d06f1b
ba71816514eb515f0a7c29de61ddeca9d2939551
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 3 changesets (bug 1541546) for causing build bustages. CLOSED TREE Backed out changeset 895863144707 (bug 1541546) Backed out changeset 4da6fb98e8f9 (bug 1541546) Backed out changeset ba71816514eb (bug 1541546)
gfx/src/X11UndefineNone.h
layout/generic/nsColumnSetFrame.cpp
layout/generic/nsImageFrame.cpp
layout/painting/nsCSSRendering.cpp
layout/painting/nsCSSRenderingGradients.cpp
layout/style/ComputedStyle.cpp
layout/style/ComputedStyle.h
layout/style/GeckoBindings.cpp
layout/style/ServoBindings.toml
layout/style/ServoStyleConstsForwards.h
layout/style/StyleColor.cpp
layout/style/StyleColorInlines.h
layout/style/StyleComplexColor.cpp
layout/style/StyleComplexColor.h
layout/style/moz.build
layout/style/nsComputedDOMStyle.cpp
layout/style/nsComputedDOMStyle.h
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/xul/nsTextBoxFrame.cpp
layout/xul/tree/nsTreeBodyFrame.cpp
servo/components/style/gecko_bindings/sugar/mod.rs
servo/components/style/gecko_bindings/sugar/style_complex_color.rs
servo/components/style/properties/gecko.mako.rs
servo/components/style/properties/properties.mako.rs
servo/components/style/values/animated/color.rs
servo/components/style/values/computed/color.rs
servo/components/style/values/computed/ui.rs
servo/components/style/values/generics/color.rs
servo/components/style/values/generics/ui.rs
servo/components/style/values/specified/color.rs
servo/ports/geckolib/cbindgen.toml
widget/cocoa/nsNativeThemeCocoa.mm
widget/windows/nsNativeThemeWin.cpp
--- a/gfx/src/X11UndefineNone.h
+++ b/gfx/src/X11UndefineNone.h
@@ -22,21 +22,16 @@
 #endif
 
 // X11 also defines Always, which conflicts with some style system enum variant
 // names, so get rid of that too, given we don't use it anywhere else.
 #ifdef Always
 #  undef Always
 #endif
 
-// And Complex...
-#ifdef Complex
-#  undef Complex
-#endif
-
 // X11/Xlib.h also defines True and False, get rid of those too for
 // the same reasons as above...
 #ifdef True
 #  undef True
 #  define X11True 1
 #endif
 #ifdef False
 #  undef False
--- a/layout/generic/nsColumnSetFrame.cpp
+++ b/layout/generic/nsColumnSetFrame.cpp
@@ -206,23 +206,23 @@ void nsColumnSetFrame::CreateBorderRende
   // the column rule as the left border. PaintBorder() does all the rendering
   // for us, so we not only save an enormous amount of code but we'll support
   // all the line styles that we support on borders!
   nsStyleBorder border(*presContext->Document());
   Sides skipSides;
   if (isVertical) {
     border.SetBorderWidth(eSideTop, ruleWidth);
     border.SetBorderStyle(eSideTop, ruleStyle);
-    border.mBorderTopColor = StyleColor::FromColor(ruleColor);
+    border.mBorderTopColor = StyleComplexColor::FromColor(ruleColor);
     skipSides |= mozilla::eSideBitsLeftRight;
     skipSides |= mozilla::eSideBitsBottom;
   } else {
     border.SetBorderWidth(eSideLeft, ruleWidth);
     border.SetBorderStyle(eSideLeft, ruleStyle);
-    border.mBorderLeftColor = StyleColor::FromColor(ruleColor);
+    border.mBorderLeftColor = StyleComplexColor::FromColor(ruleColor);
     skipSides |= mozilla::eSideBitsTopBottom;
     skipSides |= mozilla::eSideBitsRight;
   }
   // If we use box-decoration-break: slice (the default), the border
   // renderers will require clipping if we have continuations (see the
   // aNeedsClip parameter to ConstructBorderRenderer in nsCSSRendering).
   //
   // Since it doesn't matter which box-decoration-break we use since
--- a/layout/generic/nsImageFrame.cpp
+++ b/layout/generic/nsImageFrame.cpp
@@ -1257,17 +1257,17 @@ void nsImageFrame::DisplayAltText(nsPres
     firstLine = false;
   }
 }
 
 struct nsRecessedBorder : public nsStyleBorder {
   nsRecessedBorder(nscoord aBorderWidth, nsPresContext* aPresContext)
       : nsStyleBorder(*aPresContext->Document()) {
     NS_FOR_CSS_SIDES(side) {
-      BorderColorFor(side) = StyleColor::Black();
+      BorderColorFor(side) = StyleComplexColor::Black();
       mBorder.Side(side) = aBorderWidth;
       // Note: use SetBorderStyle here because we want to affect
       // mComputedBorder
       SetBorderStyle(side, StyleBorderStyle::Inset);
     }
   }
 };
 
--- a/layout/painting/nsCSSRendering.cpp
+++ b/layout/painting/nsCSSRendering.cpp
@@ -629,17 +629,17 @@ ImgDrawResult nsCSSRendering::PaintBorde
         *styleBorder, aComputedStyle, aFlags, aSkipSides);
   }
 
   nsStyleBorder newStyleBorder(*styleBorder);
 
   NS_FOR_CSS_SIDES(side) {
     nscolor color = aComputedStyle->GetVisitedDependentColor(
         nsStyleBorder::BorderColorFieldFor(side));
-    newStyleBorder.BorderColorFor(side) = StyleColor::FromColor(color);
+    newStyleBorder.BorderColorFor(side) = StyleComplexColor::FromColor(color);
   }
   return PaintBorderWithStyleBorder(aPresContext, aRenderingContext, aForFrame,
                                     aDirtyRect, aBorderArea, newStyleBorder,
                                     aComputedStyle, aFlags, aSkipSides);
 }
 
 Maybe<nsCSSBorderRenderer> nsCSSRendering::CreateBorderRenderer(
     nsPresContext* aPresContext, DrawTarget* aDrawTarget, nsIFrame* aForFrame,
@@ -655,17 +655,17 @@ Maybe<nsCSSBorderRenderer> nsCSSRenderin
         *styleBorder, aComputedStyle, aOutBorderIsEmpty, aSkipSides);
   }
 
   nsStyleBorder newStyleBorder(*styleBorder);
 
   NS_FOR_CSS_SIDES(side) {
     nscolor color = aComputedStyle->GetVisitedDependentColor(
         nsStyleBorder::BorderColorFieldFor(side));
-    newStyleBorder.BorderColorFor(side) = StyleColor::FromColor(color);
+    newStyleBorder.BorderColorFor(side) = StyleComplexColor::FromColor(color);
   }
   return CreateBorderRendererWithStyleBorder(
       aPresContext, aDrawTarget, aForFrame, aDirtyRect, aBorderArea,
       newStyleBorder, aComputedStyle, aOutBorderIsEmpty, aSkipSides);
 }
 
 ImgDrawResult nsCSSRendering::CreateWebRenderCommandsForBorder(
     nsDisplayItem* aItem, nsIFrame* aForFrame, const nsRect& aBorderArea,
@@ -801,17 +801,17 @@ static nsCSSBorderRenderer ConstructBord
   Rect dirtyRect = NSRectToRect(aDirtyRect, oneDevPixel);
 
   StyleBorderStyle borderStyles[4];
   nscolor borderColors[4];
 
   // pull out styles, colors
   NS_FOR_CSS_SIDES(i) {
     borderStyles[i] = aStyleBorder.GetBorderStyle(i);
-    borderColors[i] = aStyleBorder.BorderColorFor(i).CalcColor(*aComputedStyle);
+    borderColors[i] = aStyleBorder.BorderColorFor(i).CalcColor(aComputedStyle);
   }
 
   PrintAsFormatString(
       " borderStyles: %d %d %d %d\n", static_cast<int>(borderStyles[0]),
       static_cast<int>(borderStyles[1]), static_cast<int>(borderStyles[2]),
       static_cast<int>(borderStyles[3]));
 
   Document* document = nullptr;
@@ -1941,17 +1941,17 @@ static bool IsOpaqueBorderEdge(const nsS
 
   // If we're using a border image, assume it's not fully opaque,
   // because we may not even have the image loaded at this point, and
   // even if we did, checking whether the relevant tile is fully
   // opaque would be too much work.
   if (aBorder.mBorderImageSource.GetType() != eStyleImageType_Null)
     return false;
 
-  StyleColor color = aBorder.BorderColorFor(aSide);
+  StyleComplexColor color = aBorder.BorderColorFor(aSide);
   // We don't know the foreground color here, so if it's being used
   // we must assume it might be transparent.
   return !color.MaybeTransparent();
 }
 
 /**
  * Returns true if all border edges are either missing or opaque.
  */
@@ -2285,57 +2285,47 @@ static void DrawBackgroundColor(nsCSSRen
 
   RefPtr<Path> roundedRect =
       MakePathForRoundedRect(*drawTarget, bgAreaGfx, aClipState.mClippedRadii);
   aCtx->SetPath(roundedRect);
   aCtx->Fill();
   aCtx->Restore();
 }
 
-enum class ScrollbarColorKind {
-  Thumb,
-  Track,
-};
-
 static Maybe<nscolor> CalcScrollbarColor(nsIFrame* aFrame,
-                                         ScrollbarColorKind aKind) {
+                                         StyleComplexColor nsStyleUI::*aColor) {
   ComputedStyle* scrollbarStyle = nsLayoutUtils::StyleForScrollbar(aFrame);
-  const auto& colors = scrollbarStyle->StyleUI()->mScrollbarColor;
-  if (colors.IsAuto()) {
+  auto color = scrollbarStyle->StyleUI()->*aColor;
+  if (color.IsAuto()) {
     return Nothing();
   }
-  const auto& color = aKind == ScrollbarColorKind::Thumb
-                          ? colors.AsColors().thumb
-                          : colors.AsColors().track;
-  return Some(color.CalcColor(*scrollbarStyle));
+  return Some(color.CalcColor(scrollbarStyle));
 }
 
 static nscolor GetBackgroundColor(nsIFrame* aFrame,
                                   ComputedStyle* aComputedStyle) {
+  Maybe<nscolor> overrideColor = Nothing();
   switch (aComputedStyle->StyleDisplay()->mAppearance) {
     case StyleAppearance::ScrollbarthumbVertical:
-    case StyleAppearance::ScrollbarthumbHorizontal: {
-      if (Maybe<nscolor> overrideColor =
-              CalcScrollbarColor(aFrame, ScrollbarColorKind::Thumb)) {
-        return *overrideColor;
-      }
+    case StyleAppearance::ScrollbarthumbHorizontal:
+      overrideColor =
+          CalcScrollbarColor(aFrame, &nsStyleUI::mScrollbarFaceColor);
       break;
-    }
     case StyleAppearance::ScrollbarVertical:
     case StyleAppearance::ScrollbarHorizontal:
-    case StyleAppearance::Scrollcorner: {
-      if (Maybe<nscolor> overrideColor =
-              CalcScrollbarColor(aFrame, ScrollbarColorKind::Track)) {
-        return *overrideColor;
-      }
+    case StyleAppearance::Scrollcorner:
+      overrideColor =
+          CalcScrollbarColor(aFrame, &nsStyleUI::mScrollbarTrackColor);
       break;
-    }
     default:
       break;
   }
+  if (overrideColor.isSome()) {
+    return *overrideColor;
+  }
   return aComputedStyle->GetVisitedDependentColor(
       &nsStyleBackground::mBackgroundColor);
 }
 
 nscolor nsCSSRendering::DetermineBackgroundColor(nsPresContext* aPresContext,
                                                  ComputedStyle* aComputedStyle,
                                                  nsIFrame* aFrame,
                                                  bool& aDrawBackgroundImage,
--- a/layout/painting/nsCSSRenderingGradients.cpp
+++ b/layout/painting/nsCSSRenderingGradients.cpp
@@ -576,31 +576,31 @@ static nsTArray<ColorStop> ComputeColorS
     } else {
       // Other stops with no specified position get their position assigned
       // later by interpolation, see below.
       // Remember where the run of stops with no specified position starts,
       // if it starts here.
       if (firstUnsetPosition < 0) {
         firstUnsetPosition = i;
       }
-      auto stopColor = stop.mColor.CalcColor(*aComputedStyle);
+      auto stopColor = stop.mColor.CalcColor(aComputedStyle);
       stops.AppendElement(
           ColorStop(0, stop.mIsInterpolationHint, Color::FromABGR(stopColor)));
       continue;
     }
 
     if (i > 0) {
       // Prevent decreasing stop positions by advancing this position
       // to the previous stop position, if necessary
       double previousPosition = firstUnsetPosition > 0
                                     ? stops[firstUnsetPosition - 1].mPosition
                                     : stops[i - 1].mPosition;
       position = std::max(position, previousPosition);
     }
-    auto stopColor = stop.mColor.CalcColor(*aComputedStyle);
+    auto stopColor = stop.mColor.CalcColor(aComputedStyle);
     stops.AppendElement(ColorStop(position, stop.mIsInterpolationHint,
                                   Color::FromABGR(stopColor)));
     if (firstUnsetPosition > 0) {
       // Interpolate positions for all stops that didn't have a specified
       // position
       double p = stops[firstUnsetPosition - 1].mPosition;
       double d = (stops[i].mPosition - p) / (i - firstUnsetPosition + 1);
       for (uint32_t j = firstUnsetPosition; j < i; ++j) {
--- a/layout/style/ComputedStyle.cpp
+++ b/layout/style/ComputedStyle.cpp
@@ -272,54 +272,43 @@ static nscolor GetVisitedDependentColorI
   if (ComputedStyle* visitedStyle = aSc->GetStyleIfVisited()) {
     colors[1] = aColorFunc(visitedStyle);
     return ComputedStyle::CombineVisitedColors(colors,
                                                aSc->RelevantLinkVisited());
   }
   return colors[0];
 }
 
-static nscolor ExtractColor(const ComputedStyle& aStyle,
-                            const nscolor& aColor) {
+static nscolor ExtractColor(ComputedStyle* aStyle, const nscolor& aColor) {
   return aColor;
 }
 
-static nscolor ExtractColor(const ComputedStyle& aStyle,
-                            const StyleColor& aColor) {
+static nscolor ExtractColor(ComputedStyle* aStyle,
+                            const StyleComplexColor& aColor) {
   return aColor.CalcColor(aStyle);
 }
 
-// Currently caret-color, the only property in the list which is a ColorOrAuto,
-// always maps auto to currentcolor.
-static nscolor ExtractColor(const ComputedStyle& aStyle,
-                            const StyleColorOrAuto& aColor) {
-  if (aColor.IsAuto()) {
-    return ExtractColor(aStyle, StyleColor::CurrentColor());
-  }
-  return ExtractColor(aStyle, aColor.AsColor());
-}
-
-static nscolor ExtractColor(ComputedStyle& aStyle,
+static nscolor ExtractColor(ComputedStyle* aStyle,
                             const nsStyleSVGPaint& aPaintServer) {
   return aPaintServer.Type() == eStyleSVGPaintType_Color
-             ? aPaintServer.GetColor(&aStyle)
+             ? aPaintServer.GetColor(aStyle)
              : NS_RGBA(0, 0, 0, 0);
 }
 
 #define STYLE_FIELD(struct_, field_) aField == &struct_::field_ ||
 #define STYLE_STRUCT(name_, fields_)                                           \
   template <>                                                                  \
   nscolor ComputedStyle::GetVisitedDependentColor(                             \
       decltype(nsStyle##name_::MOZ_ARG_1 fields_) nsStyle##name_::*aField) {   \
     MOZ_ASSERT(MOZ_FOR_EACH(STYLE_FIELD, (nsStyle##name_, ), fields_) false,   \
                "Getting visited-dependent color for a field in nsStyle" #name_ \
                " which is not listed in nsCSSVisitedDependentPropList.h");     \
     return GetVisitedDependentColorInternal(                                   \
         this, [aField](ComputedStyle* sc) {                                    \
-          return ExtractColor(*sc, sc->Style##name_()->*aField);               \
+          return ExtractColor(sc, sc->Style##name_()->*aField);                \
         });                                                                    \
   }
 #include "nsCSSVisitedDependentPropList.h"
 #undef STYLE_STRUCT
 #undef STYLE_FIELD
 
 struct ColorIndexSet {
   uint8_t colorIndex, alphaIndex;
--- a/layout/style/ComputedStyle.h
+++ b/layout/style/ComputedStyle.h
@@ -13,19 +13,19 @@
 #include <algorithm>
 #include "mozilla/Assertions.h"
 #include "mozilla/CachedInheritingStyles.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/PseudoStyleType.h"
 #include "mozilla/ServoComputedData.h"
 #include "mozilla/ServoTypes.h"
 #include "mozilla/ServoUtils.h"
+#include "mozilla/StyleComplexColor.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsCSSPseudoElements.h"
-#include "nsColor.h"
 
 #include "nsStyleStructFwd.h"
 
 enum nsChangeHint : uint32_t;
 class nsIPresShell;
 class nsPresContext;
 class nsWindowSizes;
 
--- a/layout/style/GeckoBindings.cpp
+++ b/layout/style/GeckoBindings.cpp
@@ -1221,17 +1221,17 @@ nsStyleGradient* Gecko_CreateGradient(ui
 
   result->mAngle.SetNoneValue();
   result->mBgPosX.SetNoneValue();
   result->mBgPosY.SetNoneValue();
   result->mRadiusX.SetNoneValue();
   result->mRadiusY.SetNoneValue();
 
   nsStyleGradientStop dummyStop = {nsStyleCoord(eStyleUnit_None),
-                                   StyleColor::Black(), 0};
+                                   StyleComplexColor::Black(), 0};
 
   for (uint32_t i = 0; i < aStopCount; i++) {
     result->mStops.AppendElement(dummyStop);
   }
 
   return result;
 }
 
--- a/layout/style/ServoBindings.toml
+++ b/layout/style/ServoBindings.toml
@@ -90,16 +90,17 @@ rusty-enums = [
     "mozilla::StyleShapeRadius",
     "mozilla::StyleWindowDragging",
     "mozilla::StyleAnimationPlayState",
     "mozilla::StyleOrient",
     "mozilla::StyleBoxSizing",
     "mozilla::StyleClear",
     "mozilla::StyleColumnFill",
     "mozilla::StyleColumnSpan",
+    "mozilla::StyleComplexColor_Tag",
     "mozilla::StyleFloat",
     "mozilla::StyleImageOrientation",
     "mozilla::StyleUserModify",
     "mozilla::StyleUserInput",
     "mozilla::StyleBoxDirection",
     "mozilla::StyleTextJustify",
     "mozilla::StyleHyphens",
     "mozilla::StyleShapeSourceType",
@@ -453,20 +454,16 @@ cbindgen-types = [
     { gecko = "StyleWillChangeBits", servo = "values::specified::box_::WillChangeBits" },
     { gecko = "StyleTextDecorationLine", servo = "values::computed::TextDecorationLine" },
     { gecko = "StyleMozListReversed", servo = "values::computed::MozListReversed" },
     { gecko = "StyleOwned", servo = "gecko_bindings::sugar::ownership::Owned" },
     { gecko = "StyleOwnedOrNull", servo = "gecko_bindings::sugar::ownership::OwnedOrNull" },
     { gecko = "StyleStrong", servo = "gecko_bindings::sugar::ownership::Strong" },
     { gecko = "StyleGenericFontFamily", servo = "values::computed::font::GenericFontFamily" },
     { gecko = "StyleFontFamilyNameSyntax", servo = "values::computed::font::FontFamilyNameSyntax" },
-    { gecko = "StyleGenericColor", servo = "values::generics::color::Color" },
-    { gecko = "StyleGenericColorOrAuto", servo = "values::generics::color::ColorOrAuto" },
-    { gecko = "StyleGenericScrollbarColor", servo = "values::generics::ui::ScrollbarColor" },
-    { gecko = "StyleRGBA", servo = "cssparser::RGBA" },
 ]
 
 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/ServoStyleConstsForwards.h
+++ b/layout/style/ServoStyleConstsForwards.h
@@ -25,17 +25,16 @@
 #  include "mozilla/ServoBindingTypes.h"
 #  include "nsCSSPropertyID.h"
 #  include "nsCompatibility.h"
 
 struct RawServoAnimationValueTable;
 struct RawServoAnimationValueMap;
 
 class nsAtom;
-class nsIFrame;
 class nsINode;
 class nsCSSPropertyIDSet;
 class nsPresContext;
 class nsSimpleContentList;
 struct nsCSSValueSharedList;
 struct nsTimingFunction;
 
 class gfxFontFeatureValueSet;
@@ -54,18 +53,16 @@ namespace nsStyleTransformMatrix {
 enum class MatrixTransformOperator : uint8_t;
 }
 
 template <typename T>
 class nsMainThreadPtrHolder;
 
 namespace mozilla {
 
-class ComputedStyle;
-
 using Matrix4x4Components = float[16];
 using StyleMatrix4x4Components = Matrix4x4Components;
 
 struct Keyframe;
 struct PropertyStyleAnimationValuePair;
 
 using ComputedKeyframeValues = nsTArray<PropertyStyleAnimationValuePair>;
 
rename from layout/style/StyleColor.cpp
rename to layout/style/StyleComplexColor.cpp
--- a/layout/style/StyleColor.cpp
+++ b/layout/style/StyleComplexColor.cpp
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-#include "mozilla/StyleColorInlines.h"
+#include "mozilla/StyleComplexColor.h"
 
 #include "mozilla/ComputedStyle.h"
 #include "mozilla/ComputedStyleInlines.h"
 #include "nsIFrame.h"
 #include "nsStyleStruct.h"
 
 using namespace mozilla;
 
@@ -41,52 +41,47 @@ static nscolor LinearBlendColors(nscolor
   }
 
   auto r = ClampColor((p1 * r1 + p2 * r2) / a);
   auto g = ClampColor((p1 * g1 + p2 * g2) / a);
   auto b = ClampColor((p1 * b1 + p2 * b2) / a);
   return NS_RGBA(r, g, b, NSToIntRound(a * 255));
 }
 
-template <>
-bool StyleColor::MaybeTransparent() const {
+bool StyleComplexColor::MaybeTransparent() const {
   // We know that the color is opaque when it's a numeric color with
   // alpha == 255.
   // TODO(djg): Should we extend this to check Complex with bgRatio =
   // 0, and fgRatio * alpha >= 255?
-  return !IsNumeric() || AsNumeric().alpha != 255;
-}
-
-static nscolor RGBAToNSColor(const StyleRGBA& aRGBA) {
-  return NS_RGBA(aRGBA.red, aRGBA.green, aRGBA.blue, aRGBA.alpha);
+  return mTag != eNumeric || NS_GET_A(mColor) != 255;
 }
 
-template <>
-nscolor StyleColor::CalcColor(nscolor aForegroundColor) const {
-  if (IsNumeric()) {
-    return RGBAToNSColor(AsNumeric());
+nscolor StyleComplexColor::CalcColor(nscolor aForegroundColor) const {
+  switch (mTag) {
+    case eNumeric:
+      return mColor;
+    case eForeground:
+    case eAuto:
+      return aForegroundColor;
+    case eComplex:
+      return LinearBlendColors(mColor, mBgRatio, aForegroundColor, mFgRatio);
+    default:
+      MOZ_ASSERT_UNREACHABLE("StyleComplexColor has invalid mTag");
+      return mColor;
   }
-  if (IsCurrentColor()) {
-    return aForegroundColor;
-  }
-  MOZ_ASSERT(IsComplex());
-  const auto& complex = AsComplex();
-  return LinearBlendColors(RGBAToNSColor(complex.color), complex.ratios.bg,
-                           aForegroundColor, complex.ratios.fg);
 }
 
-template <>
-nscolor StyleColor::CalcColor(const ComputedStyle& aStyle) const {
+nscolor StyleComplexColor::CalcColor(mozilla::ComputedStyle* aStyle) const {
   // Common case that is numeric color, which is pure background, we
   // can skip resolving StyleColor().
   // TODO(djg): Is this optimization worth it?
-  if (IsNumeric()) {
-    return RGBAToNSColor(AsNumeric());
+  if (mTag == eNumeric) {
+    return mColor;
   }
 
-  auto fgColor = aStyle.StyleColor()->mColor;
+  MOZ_ASSERT(aStyle);
+  auto fgColor = aStyle->StyleColor()->mColor;
   return CalcColor(fgColor);
 }
 
-template <>
-nscolor StyleColor::CalcColor(const nsIFrame* aFrame) const {
-  return CalcColor(*aFrame->Style());
+nscolor StyleComplexColor::CalcColor(const nsIFrame* aFrame) const {
+  return CalcColor(aFrame->Style());
 }
rename from layout/style/StyleColorInlines.h
rename to layout/style/StyleComplexColor.h
--- a/layout/style/StyleColorInlines.h
+++ b/layout/style/StyleComplexColor.h
@@ -1,49 +1,134 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-/* Inline functions for StyleColor (aka values::computed::Color) */
+/* represent a color combines a numeric color and currentcolor */
 
-#ifndef mozilla_StyleColorInlines_h_
-#define mozilla_StyleColorInlines_h_
+#ifndef mozilla_StyleComplexColor_h_
+#define mozilla_StyleComplexColor_h_
 
 #include "nsColor.h"
-#include "mozilla/ServoStyleConsts.h"
+
+class nsIFrame;
 
 namespace mozilla {
 
-template<>
-inline StyleColor StyleColor::FromColor(nscolor aColor) {
-  return StyleColor::Numeric({NS_GET_R(aColor), NS_GET_G(aColor),
-                              NS_GET_B(aColor), NS_GET_A(aColor)});
-}
+class ComputedStyle;
+
+/**
+ * This struct represents a combined color from a numeric color and
+ * the current foreground color (currentcolor keyword).
+ * Conceptually, the formula is "color * q + currentcolor * p"
+ * where p is mFgRatio and q is mBgRatio.
+ *
+ * It can also represent an "auto" value, which is valid for some
+ * properties. See comment of `Tag::eAuto`.
+ */
+class StyleComplexColor final {
+ public:
+  static StyleComplexColor FromColor(nscolor aColor) {
+    return {aColor, 0, eNumeric};
+  }
+  static StyleComplexColor CurrentColor() {
+    return {NS_RGBA(0, 0, 0, 0), 1, eForeground};
+  }
+  static StyleComplexColor Auto() { return {NS_RGBA(0, 0, 0, 0), 1, eAuto}; }
 
-template<>
-inline StyleColor StyleColor::Black() {
-  return FromColor(NS_RGB(0, 0, 0));
-}
+  static StyleComplexColor Black() {
+    return StyleComplexColor::FromColor(NS_RGB(0, 0, 0));
+  }
+  static StyleComplexColor White() {
+    return StyleComplexColor::FromColor(NS_RGB(255, 255, 255));
+  }
+  static StyleComplexColor Transparent() {
+    return StyleComplexColor::FromColor(NS_RGBA(0, 0, 0, 0));
+  }
+
+  bool IsAuto() const { return mTag == eAuto; }
+  bool IsCurrentColor() const { return mTag == eForeground; }
+
+  bool operator==(const StyleComplexColor& aOther) const {
+    if (mTag != aOther.mTag) {
+      return false;
+    }
+
+    switch (mTag) {
+      case eAuto:
+      case eForeground:
+        return true;
+      case eNumeric:
+        return mColor == aOther.mColor;
+      case eComplex:
+        return (mBgRatio == aOther.mBgRatio && mFgRatio == aOther.mFgRatio &&
+                mColor == aOther.mColor);
+      default:
+        MOZ_ASSERT_UNREACHABLE("Unexpected StyleComplexColor type.");
+        return false;
+    }
+  }
 
-template<>
-inline StyleColor StyleColor::White() {
-  return FromColor(NS_RGB(255, 255, 255));
-}
+  bool operator!=(const StyleComplexColor& aOther) const {
+    return !(*this == aOther);
+  }
+
+  /**
+   * Is it possible that this StyleComplexColor is transparent?
+   */
+  bool MaybeTransparent() const;
+
+  /**
+   * Compute the color for this StyleComplexColor, taking into account
+   * the foreground color, aForegroundColor.
+   */
+  nscolor CalcColor(nscolor aForegroundColor) const;
+
+  /**
+   * Compute the color for this StyleComplexColor, taking into account
+   * the foreground color from aStyle.
+   */
+  nscolor CalcColor(mozilla::ComputedStyle* aStyle) const;
+
+  /**
+   * Compute the color for this StyleComplexColor, taking into account
+   * the foreground color from aFrame's ComputedStyle.
+   */
+  nscolor CalcColor(const nsIFrame* aFrame) const;
 
-template<>
-inline StyleColor StyleColor::Transparent() {
-  return FromColor(NS_RGBA(0, 0, 0, 0));
-}
+ private:
+  enum Tag : uint8_t {
+    // This represents a computed-value time auto value. This
+    // indicates that this value should not be interpolatable with
+    // other colors. Other fields represent a currentcolor and
+    // properties can decide whether that should be used.
+    eAuto,
+    // This represents a numeric color; no currentcolor component.
+    eNumeric,
+    // This represents the current foreground color, currentcolor; no
+    // numeric color component.
+    eForeground,
+    // This represents a linear combination of numeric color and the
+    // foreground color: "mColor * mBgRatio + currentcolor *
+    // mFgRatio".
+    eComplex,
+  };
 
-template <>
-nscolor StyleColor::CalcColor(nscolor aForegroundColor) const;
+  StyleComplexColor(nscolor aColor, float aFgRatio, Tag aTag)
+      : mColor(aColor),
+        mBgRatio(1.f - aFgRatio),
+        mFgRatio(aFgRatio),
+        mTag(aTag) {
+    MOZ_ASSERT(mTag != eNumeric || aFgRatio == 0.);
+    MOZ_ASSERT(!(mTag == eAuto || mTag == eForeground) || aFgRatio == 1.);
+  }
 
-template <>
-nscolor StyleColor::CalcColor(const ComputedStyle&) const;
-
-template <>
-nscolor StyleColor::CalcColor(const nsIFrame*) const;
+  nscolor mColor;
+  float mBgRatio;
+  float mFgRatio;
+  Tag mTag;
+};
 
 }  // namespace mozilla
 
-#endif  // mozilla_StyleColor_h_
+#endif  // mozilla_StyleComplexColor_h_
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -103,17 +103,17 @@ EXPORTS.mozilla += [
     'ServoStyleConstsForwards.h',
     'ServoStyleSet.h',
     'ServoStyleSetInlines.h',
     'ServoTraversalStatistics.h',
     'ServoTypes.h',
     'ServoUtils.h',
     'SheetType.h',
     'StyleAnimationValue.h',
-    'StyleColorInlines.h',
+    'StyleComplexColor.h',
     'StyleSheet.h',
     'StyleSheetInfo.h',
     'StyleSheetInlines.h',
     'URLExtraData.h',
     'UserAgentStyleSheetID.h',
     'UserAgentStyleSheetList.h',
 ]
 
@@ -218,17 +218,17 @@ UNIFIED_SOURCES += [
     'PseudoStyleType.cpp',
     'Rule.cpp',
     'ServoCSSParser.cpp',
     'ServoCSSRuleList.cpp',
     'ServoElementSnapshot.cpp',
     'ServoStyleSet.cpp',
     'StreamLoader.cpp',
     'StyleAnimationValue.cpp',
-    'StyleColor.cpp',
+    'StyleComplexColor.cpp',
     'StyleSheet.cpp',
     'URLExtraData.cpp',
 ]
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'
 
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -1036,18 +1036,18 @@ already_AddRefed<CSSValue> nsComputedDOM
 void nsComputedDOMStyle::SetToRGBAColor(nsROCSSPrimitiveValue* aValue,
                                         nscolor aColor) {
   nsAutoString string;
   nsStyleUtil::GetSerializedColorValue(aColor, string);
   aValue->SetString(string);
 }
 
 void nsComputedDOMStyle::SetValueFromComplexColor(
-    nsROCSSPrimitiveValue* aValue, const mozilla::StyleColor& aColor) {
-  SetToRGBAColor(aValue, aColor.CalcColor(*mComputedStyle));
+    nsROCSSPrimitiveValue* aValue, const StyleComplexColor& aColor) {
+  SetToRGBAColor(aValue, aColor.CalcColor(mComputedStyle));
 }
 
 already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetColor() {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetToRGBAColor(val, StyleColor()->mColor);
   return val.forget();
 }
 
@@ -1853,31 +1853,34 @@ already_AddRefed<CSSValue> nsComputedDOM
 }
 
 already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetScrollSnapPointsY() {
   return GetScrollSnapPoints(StyleDisplay()->mScrollSnapPointsY);
 }
 
 already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetScrollbarColor() {
   const nsStyleUI* ui = StyleUI();
-  if (ui->mScrollbarColor.IsAuto()) {
+  MOZ_ASSERT(
+      ui->mScrollbarFaceColor.IsAuto() == ui->mScrollbarTrackColor.IsAuto(),
+      "Whether the two colors are auto should be identical");
+
+  if (ui->mScrollbarFaceColor.IsAuto()) {
     RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     val->SetIdent(eCSSKeyword_auto);
     return val.forget();
   }
 
   RefPtr<nsDOMCSSValueList> list = GetROCSSValueList(false);
-  auto put = [this, &list](const mozilla::StyleColor& color) {
+  auto put = [this, &list](const StyleComplexColor& color) {
     RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
     SetValueFromComplexColor(val, color);
     list->AppendCSSValue(val.forget());
   };
-  auto& colors = ui->mScrollbarColor.AsColors();
-  put(colors.thumb);
-  put(colors.track);
+  put(ui->mScrollbarFaceColor);
+  put(ui->mScrollbarTrackColor);
   return list.forget();
 }
 
 already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetOutlineWidth() {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetAppUnits(StyleOutline()->GetOutlineWidth());
   return val.forget();
 }
@@ -1994,17 +1997,17 @@ already_AddRefed<CSSValue> nsComputedDOM
   return val.forget();
 }
 
 already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetTextDecoration() {
   const nsStyleTextReset* textReset = StyleTextReset();
 
   bool isInitialStyle =
       textReset->mTextDecorationStyle == NS_STYLE_TEXT_DECORATION_STYLE_SOLID;
-  const mozilla::StyleColor& color = textReset->mTextDecorationColor;
+  StyleComplexColor color = textReset->mTextDecorationColor;
 
   RefPtr<nsROCSSPrimitiveValue> textDecorationLine = new nsROCSSPrimitiveValue;
 
   {
     nsAutoString decorationLine;
     Servo_GetPropertyValue(mComputedStyle, eCSSProperty_text_decoration_line,
                            &decorationLine);
     textDecorationLine->SetString(decorationLine);
@@ -2145,21 +2148,17 @@ already_AddRefed<CSSValue> nsComputedDOM
   return val.forget();
 }
 
 static_assert(NS_STYLE_UNICODE_BIDI_NORMAL == 0,
               "unicode-bidi style constants not as expected");
 
 already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetCaretColor() {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-  if (StyleUI()->mCaretColor.IsAuto()) {
-    SetToRGBAColor(val, StyleColor()->mColor);
-  } else {
-    SetValueFromComplexColor(val, StyleUI()->mCaretColor.AsColor());
-  }
+  SetValueFromComplexColor(val, StyleUI()->mCaretColor);
   return val.forget();
 }
 
 already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetBoxFlex() {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetNumber(StyleXUL()->mBoxFlex);
   return val.forget();
 }
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -5,17 +5,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 /* DOM object returned from element.getComputedStyle() */
 
 #ifndef nsComputedDOMStyle_h__
 #define nsComputedDOMStyle_h__
 
 #include "mozilla/Attributes.h"
-#include "mozilla/StyleColorInlines.h"
+#include "mozilla/StyleComplexColor.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/dom/Element.h"
 #include "nsCOMPtr.h"
 #include "nsContentUtils.h"
 #include "nscore.h"
 #include "nsDOMCSSDeclaration.h"
 #include "mozilla/ComputedStyle.h"
 #include "nsIWeakReferenceUtils.h"
@@ -365,17 +365,17 @@ class nsComputedDOMStyle final : public 
   already_AddRefed<CSSValue> DoGetPaintOrder();
 
   // For working around a MSVC bug. See related comment in
   // GenerateComputedDOMStyleGenerated.py.
   already_AddRefed<CSSValue> DummyGetter();
 
   /* Helper functions */
   void SetValueFromComplexColor(nsROCSSPrimitiveValue* aValue,
-                                const mozilla::StyleColor& aColor);
+                                const mozilla::StyleComplexColor& aColor);
   void SetValueToPosition(const mozilla::Position& aPosition,
                           nsDOMCSSValueList* aValueList);
   void SetValueToURLValue(const mozilla::css::URLValue* aURL,
                           nsROCSSPrimitiveValue* aValue);
 
   void SetValueToSize(nsROCSSPrimitiveValue* aValue, const mozilla::StyleSize&,
                       nscoord aMinAppUnits = nscoord_MIN,
                       nscoord aMaxAppUnits = nscoord_MAX);
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -254,20 +254,20 @@ nsStyleBorder::nsStyleBorder(const Docum
           StyleRectWithAllSides(StyleNonNegativeLengthOrNumber::Number(0.))),
       mBorderImageSlice(
           {StyleRectWithAllSides(StyleNumberOrPercentage::Percentage({1.})),
            false}),
       mBorderImageRepeatH(StyleBorderImageRepeat::Stretch),
       mBorderImageRepeatV(StyleBorderImageRepeat::Stretch),
       mFloatEdge(StyleFloatEdge::ContentBox),
       mBoxDecorationBreak(StyleBoxDecorationBreak::Slice),
-      mBorderTopColor(StyleColor::CurrentColor()),
-      mBorderRightColor(StyleColor::CurrentColor()),
-      mBorderBottomColor(StyleColor::CurrentColor()),
-      mBorderLeftColor(StyleColor::CurrentColor()),
+      mBorderTopColor(StyleComplexColor::CurrentColor()),
+      mBorderRightColor(StyleComplexColor::CurrentColor()),
+      mBorderBottomColor(StyleComplexColor::CurrentColor()),
+      mBorderLeftColor(StyleComplexColor::CurrentColor()),
       mComputedBorder(0, 0, 0, 0),
       mTwipsPerPixel(TwipsPerPixel(aDocument)) {
   MOZ_COUNT_CTOR(nsStyleBorder);
 
   nscoord medium = kMediumBorderWidth;
   NS_FOR_CSS_SIDES(side) {
     mBorderImageWidth.Set(side, nsStyleCoord(1.0f, eStyleUnit_Factor));
     mBorder.Side(side) = medium;
@@ -401,17 +401,17 @@ nsChangeHint nsStyleBorder::CalcDifferen
 
   return nsChangeHint(0);
 }
 
 nsStyleOutline::nsStyleOutline(const Document& aDocument)
     : mOutlineRadius(ZeroBorderRadius()),
       mOutlineWidth(kMediumBorderWidth),
       mOutlineOffset(0),
-      mOutlineColor(StyleColor::CurrentColor()),
+      mOutlineColor(StyleComplexColor::CurrentColor()),
       mOutlineStyle(StyleOutlineStyle::BorderStyle(StyleBorderStyle::None)),
       mActualOutlineWidth(0),
       mTwipsPerPixel(TwipsPerPixel(aDocument)) {
   MOZ_COUNT_CTOR(nsStyleOutline);
 }
 
 nsStyleOutline::nsStyleOutline(const nsStyleOutline& aSrc)
     : mOutlineRadius(aSrc.mOutlineRadius),
@@ -584,17 +584,17 @@ nsChangeHint nsStyleXUL::CalcDifference(
 // --------------------
 // nsStyleColumn
 //
 /* static */ const uint32_t nsStyleColumn::kMaxColumnCount;
 /* static */ const uint32_t nsStyleColumn::kColumnCountAuto;
 
 nsStyleColumn::nsStyleColumn(const Document& aDocument)
     : mColumnWidth(eStyleUnit_Auto),
-      mColumnRuleColor(StyleColor::CurrentColor()),
+      mColumnRuleColor(StyleComplexColor::CurrentColor()),
       mColumnRuleStyle(StyleBorderStyle::None),
       mColumnRuleWidth(kMediumBorderWidth),
       mTwipsPerPixel(TwipsPerPixel(aDocument)) {
   MOZ_COUNT_CTOR(nsStyleColumn);
 }
 
 nsStyleColumn::~nsStyleColumn() { MOZ_COUNT_DTOR(nsStyleColumn); }
 
@@ -1062,19 +1062,19 @@ void nsStyleFilter::SetDropShadow(nsCSSS
   mType = NS_STYLE_FILTER_DROP_SHADOW;
 }
 
 // --------------------
 // nsStyleSVGReset
 //
 nsStyleSVGReset::nsStyleSVGReset(const Document& aDocument)
     : mMask(nsStyleImageLayers::LayerType::Mask),
-      mStopColor(StyleColor::Black()),
-      mFloodColor(StyleColor::Black()),
-      mLightingColor(StyleColor::White()),
+      mStopColor(StyleComplexColor::Black()),
+      mFloodColor(StyleComplexColor::Black()),
+      mLightingColor(StyleComplexColor::White()),
       mStopOpacity(1.0f),
       mFloodOpacity(1.0f),
       mDominantBaseline(NS_STYLE_DOMINANT_BASELINE_AUTO),
       mVectorEffect(NS_STYLE_VECTOR_EFFECT_NONE),
       mMaskType(NS_STYLE_MASK_TYPE_LUMINANCE) {
   MOZ_COUNT_CTOR(nsStyleSVGReset);
 }
 
@@ -1171,20 +1171,20 @@ bool nsStyleSVGReset::HasMask() const {
     }
   }
 
   return false;
 }
 
 // nsStyleSVGPaint implementation
 nsStyleSVGPaint::nsStyleSVGPaint(nsStyleSVGPaintType aType)
-    : mPaint(StyleColor::Black()),
+    : mPaint(StyleComplexColor::Black()),
       mType(aType),
       mFallbackType(eStyleSVGFallbackType_NotSet),
-      mFallbackColor(StyleColor::Black()) {
+      mFallbackColor(StyleComplexColor::Black()) {
   MOZ_ASSERT(aType == nsStyleSVGPaintType(0) ||
              aType == eStyleSVGPaintType_None ||
              aType == eStyleSVGPaintType_Color);
 }
 
 nsStyleSVGPaint::nsStyleSVGPaint(const nsStyleSVGPaint& aSource)
     : nsStyleSVGPaint(nsStyleSVGPaintType(0)) {
   Assign(aSource);
@@ -1192,26 +1192,26 @@ nsStyleSVGPaint::nsStyleSVGPaint(const n
 
 nsStyleSVGPaint::~nsStyleSVGPaint() { Reset(); }
 
 void nsStyleSVGPaint::Reset() {
   switch (mType) {
     case eStyleSVGPaintType_None:
       break;
     case eStyleSVGPaintType_Color:
-      mPaint.mColor = StyleColor::Black();
+      mPaint.mColor = StyleComplexColor::Black();
       break;
     case eStyleSVGPaintType_Server:
       mPaint.mPaintServer->Release();
       mPaint.mPaintServer = nullptr;
       MOZ_FALLTHROUGH;
     case eStyleSVGPaintType_ContextFill:
     case eStyleSVGPaintType_ContextStroke:
       mFallbackType = eStyleSVGFallbackType_NotSet;
-      mFallbackColor = StyleColor::Black();
+      mFallbackColor = StyleComplexColor::Black();
       break;
   }
   mType = nsStyleSVGPaintType(0);
 }
 
 nsStyleSVGPaint& nsStyleSVGPaint::operator=(const nsStyleSVGPaint& aOther) {
   if (this != &aOther) {
     Assign(aOther);
@@ -1244,34 +1244,34 @@ void nsStyleSVGPaint::Assign(const nsSty
 
 void nsStyleSVGPaint::SetNone() {
   Reset();
   mType = eStyleSVGPaintType_None;
 }
 
 void nsStyleSVGPaint::SetContextValue(nsStyleSVGPaintType aType,
                                       nsStyleSVGFallbackType aFallbackType,
-                                      StyleColor aFallbackColor) {
+                                      StyleComplexColor aFallbackColor) {
   MOZ_ASSERT(aType == eStyleSVGPaintType_ContextFill ||
              aType == eStyleSVGPaintType_ContextStroke);
   Reset();
   mType = aType;
   mFallbackType = aFallbackType;
   mFallbackColor = aFallbackColor;
 }
 
-void nsStyleSVGPaint::SetColor(StyleColor aColor) {
+void nsStyleSVGPaint::SetColor(StyleComplexColor aColor) {
   Reset();
   mType = eStyleSVGPaintType_Color;
   mPaint.mColor = aColor;
 }
 
 void nsStyleSVGPaint::SetPaintServer(css::URLValue* aPaintServer,
                                      nsStyleSVGFallbackType aFallbackType,
-                                     StyleColor aFallbackColor) {
+                                     StyleComplexColor aFallbackColor) {
   MOZ_ASSERT(aPaintServer);
   Reset();
   mType = eStyleSVGPaintType_Server;
   mPaint.mPaintServer = aPaintServer;
   mPaint.mPaintServer->AddRef();
   mFallbackType = aFallbackType;
   mFallbackColor = aFallbackColor;
 }
@@ -2796,17 +2796,17 @@ nsChangeHint nsStyleImageLayers::Layer::
 }
 
 // --------------------
 // nsStyleBackground
 //
 
 nsStyleBackground::nsStyleBackground(const Document& aDocument)
     : mImage(nsStyleImageLayers::LayerType::Background),
-      mBackgroundColor(StyleColor::Transparent()) {
+      mBackgroundColor(StyleComplexColor::Transparent()) {
   MOZ_COUNT_CTOR(nsStyleBackground);
 }
 
 nsStyleBackground::nsStyleBackground(const nsStyleBackground& aSource)
     : mImage(aSource.mImage), mBackgroundColor(aSource.mBackgroundColor) {
   MOZ_COUNT_CTOR(nsStyleBackground);
 }
 
@@ -2841,18 +2841,19 @@ bool nsStyleBackground::HasFixedBackgrou
   }
   return false;
 }
 
 nscolor nsStyleBackground::BackgroundColor(const nsIFrame* aFrame) const {
   return mBackgroundColor.CalcColor(aFrame);
 }
 
-nscolor nsStyleBackground::BackgroundColor(ComputedStyle* aStyle) const {
-  return mBackgroundColor.CalcColor(*aStyle);
+nscolor nsStyleBackground::BackgroundColor(
+    mozilla::ComputedStyle* aStyle) const {
+  return mBackgroundColor.CalcColor(aStyle);
 }
 
 bool nsStyleBackground::IsTransparent(const nsIFrame* aFrame) const {
   return IsTransparent(aFrame->Style());
 }
 
 bool nsStyleBackground::IsTransparent(mozilla::ComputedStyle* aStyle) const {
   return BottomLayer().mImage.IsEmpty() && mImage.mImageCount == 1 &&
@@ -3642,17 +3643,17 @@ nsChangeHint nsStyleContent::CalcDiffere
 
 nsStyleTextReset::nsStyleTextReset(const Document& aDocument)
     : mTextOverflow(),
       mTextDecorationLine(StyleTextDecorationLine_NONE),
       mTextDecorationStyle(NS_STYLE_TEXT_DECORATION_STYLE_SOLID),
       mUnicodeBidi(NS_STYLE_UNICODE_BIDI_NORMAL),
       mInitialLetterSink(0),
       mInitialLetterSize(0.0f),
-      mTextDecorationColor(StyleColor::CurrentColor()) {
+      mTextDecorationColor(StyleComplexColor::CurrentColor()) {
   MOZ_COUNT_CTOR(nsStyleTextReset);
 }
 
 nsStyleTextReset::nsStyleTextReset(const nsStyleTextReset& aSource)
     : mTextOverflow(aSource.mTextOverflow),
       mTextDecorationLine(aSource.mTextDecorationLine),
       mTextDecorationStyle(aSource.mTextDecorationStyle),
       mUnicodeBidi(aSource.mUnicodeBidi),
@@ -3725,19 +3726,19 @@ nsStyleText::nsStyleText(const Document&
       mRubyAlign(NS_STYLE_RUBY_ALIGN_SPACE_AROUND),
       mRubyPosition(NS_STYLE_RUBY_POSITION_OVER),
       mTextSizeAdjust(NS_STYLE_TEXT_SIZE_ADJUST_AUTO),
       mTextCombineUpright(NS_STYLE_TEXT_COMBINE_UPRIGHT_NONE),
       mControlCharacterVisibility(
           nsLayoutUtils::ControlCharVisibilityDefault()),
       mTextEmphasisStyle(NS_STYLE_TEXT_EMPHASIS_STYLE_NONE),
       mTextRendering(StyleTextRendering::Auto),
-      mTextEmphasisColor(StyleColor::CurrentColor()),
-      mWebkitTextFillColor(StyleColor::CurrentColor()),
-      mWebkitTextStrokeColor(StyleColor::CurrentColor()),
+      mTextEmphasisColor(StyleComplexColor::CurrentColor()),
+      mWebkitTextFillColor(StyleComplexColor::CurrentColor()),
+      mWebkitTextStrokeColor(StyleComplexColor::CurrentColor()),
       mMozTabSize(
           StyleNonNegativeLengthOrNumber::Number(NS_STYLE_TABSIZE_INITIAL)),
       mWordSpacing(LengthPercentage::Zero()),
       mLetterSpacing({0.}),
       mLineHeight(StyleLineHeight::Normal()),
       mTextIndent(LengthPercentage::Zero()),
       mWebkitTextStrokeWidth(0),
       mTextShadow(nullptr) {
@@ -3912,30 +3913,32 @@ bool nsCursorImage::operator==(const nsC
 }
 
 nsStyleUI::nsStyleUI(const Document& aDocument)
     : mUserInput(StyleUserInput::Auto),
       mUserModify(StyleUserModify::ReadOnly),
       mUserFocus(StyleUserFocus::None),
       mPointerEvents(NS_STYLE_POINTER_EVENTS_AUTO),
       mCursor(StyleCursorKind::Auto),
-      mCaretColor(StyleColorOrAuto::Auto()),
-      mScrollbarColor(StyleScrollbarColor::Auto()) {
+      mCaretColor(StyleComplexColor::Auto()),
+      mScrollbarFaceColor(StyleComplexColor::Auto()),
+      mScrollbarTrackColor(StyleComplexColor::Auto()) {
   MOZ_COUNT_CTOR(nsStyleUI);
 }
 
 nsStyleUI::nsStyleUI(const nsStyleUI& aSource)
     : mUserInput(aSource.mUserInput),
       mUserModify(aSource.mUserModify),
       mUserFocus(aSource.mUserFocus),
       mPointerEvents(aSource.mPointerEvents),
       mCursor(aSource.mCursor),
       mCursorImages(aSource.mCursorImages),
       mCaretColor(aSource.mCaretColor),
-      mScrollbarColor(aSource.mScrollbarColor) {
+      mScrollbarFaceColor(aSource.mScrollbarFaceColor),
+      mScrollbarTrackColor(aSource.mScrollbarTrackColor) {
   MOZ_COUNT_CTOR(nsStyleUI);
 }
 
 nsStyleUI::~nsStyleUI() { MOZ_COUNT_DTOR(nsStyleUI); }
 
 void nsStyleUI::TriggerImageLoads(Document& aDocument,
                                   const nsStyleUI* aOldStyle) {
   MOZ_ASSERT(NS_IsMainThread());
@@ -3987,17 +3990,18 @@ nsChangeHint nsStyleUI::CalcDifference(c
     }
   }
 
   if (mUserFocus != aNewData.mUserFocus) {
     hint |= nsChangeHint_NeutralChange;
   }
 
   if (mCaretColor != aNewData.mCaretColor ||
-      mScrollbarColor != aNewData.mScrollbarColor) {
+      mScrollbarFaceColor != aNewData.mScrollbarFaceColor ||
+      mScrollbarTrackColor != aNewData.mScrollbarTrackColor) {
     hint |= nsChangeHint_RepaintFrame;
   }
 
   return hint;
 }
 
 //-----------------------
 // nsStyleUIReset
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -11,17 +11,17 @@
 
 #ifndef nsStyleStruct_h___
 #define nsStyleStruct_h___
 
 #include "mozilla/Attributes.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/SheetType.h"
 #include "mozilla/StaticPtr.h"
-#include "mozilla/StyleColorInlines.h"
+#include "mozilla/StyleComplexColor.h"
 #include "mozilla/UniquePtr.h"
 #include "nsColor.h"
 #include "nsCoord.h"
 #include "nsMargin.h"
 #include "nsFont.h"
 #include "nsStyleAutoArray.h"
 #include "nsStyleCoord.h"
 #include "nsStyleConsts.h"
@@ -128,17 +128,17 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
   nscoord mScriptUnconstrainedSize;
   nscoord mScriptMinSize;  // length
   float mScriptSizeMultiplier;
   RefPtr<nsAtom> mLanguage;
 };
 
 struct nsStyleGradientStop {
   nsStyleCoord mLocation;  // percent, coord, calc, none
-  mozilla::StyleColor mColor;
+  mozilla::StyleComplexColor mColor;
   bool mIsInterpolationHint;
 
   // Use ==/!= on nsStyleGradient instead of on the gradient stop.
   bool operator==(const nsStyleGradientStop&) const = delete;
   bool operator!=(const nsStyleGradientStop&) const = delete;
 };
 
 class nsStyleGradient final {
@@ -681,17 +681,17 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
   // This is defined in nsStyleStructInlines.h.
   inline bool HasLocalBackground() const;
 
   const nsStyleImageLayers::Layer& BottomLayer() const {
     return mImage.BottomLayer();
   }
 
   nsStyleImageLayers mImage;
-  mozilla::StyleColor mBackgroundColor;
+  mozilla::StyleComplexColor mBackgroundColor;
 };
 
 struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleMargin {
   explicit nsStyleMargin(const mozilla::dom::Document&);
   nsStyleMargin(const nsStyleMargin& aMargin);
   ~nsStyleMargin() { MOZ_COUNT_DTOR(nsStyleMargin); }
   void TriggerImageLoads(mozilla::dom::Document&, const nsStyleMargin*) {}
   const static bool kHasTriggerImageLoads = false;
@@ -752,25 +752,25 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
 };
 
 struct nsCSSShadowItem {
   nscoord mXOffset;
   nscoord mYOffset;
   nscoord mRadius;
   nscoord mSpread;
 
-  mozilla::StyleColor mColor;
+  mozilla::StyleComplexColor mColor;
   bool mInset;
 
   nsCSSShadowItem()
       : mXOffset(0),
         mYOffset(0),
         mRadius(0),
         mSpread(0),
-        mColor(mozilla::StyleColor::CurrentColor()),
+        mColor(mozilla::StyleComplexColor::CurrentColor()),
         mInset(false) {
     MOZ_COUNT_CTOR(nsCSSShadowItem);
   }
   ~nsCSSShadowItem() { MOZ_COUNT_DTOR(nsCSSShadowItem); }
 
   bool operator==(const nsCSSShadowItem& aOther) const {
     return (mXOffset == aOther.mXOffset && mYOffset == aOther.mYOffset &&
             mRadius == aOther.mRadius && mSpread == aOther.mSpread &&
@@ -953,52 +953,52 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
   mozilla::StyleBoxDecorationBreak mBoxDecorationBreak;
 
  protected:
   mozilla::StyleBorderStyle mBorderStyle[4];  // StyleBorderStyle::*
 
  public:
   // the colors to use for a simple border.
   // not used for -moz-border-colors
-  mozilla::StyleColor mBorderTopColor;
-  mozilla::StyleColor mBorderRightColor;
-  mozilla::StyleColor mBorderBottomColor;
-  mozilla::StyleColor mBorderLeftColor;
-
-  mozilla::StyleColor& BorderColorFor(mozilla::Side aSide) {
+  mozilla::StyleComplexColor mBorderTopColor;
+  mozilla::StyleComplexColor mBorderRightColor;
+  mozilla::StyleComplexColor mBorderBottomColor;
+  mozilla::StyleComplexColor mBorderLeftColor;
+
+  mozilla::StyleComplexColor& BorderColorFor(mozilla::Side aSide) {
     switch (aSide) {
       case mozilla::eSideTop:
         return mBorderTopColor;
       case mozilla::eSideRight:
         return mBorderRightColor;
       case mozilla::eSideBottom:
         return mBorderBottomColor;
       case mozilla::eSideLeft:
         return mBorderLeftColor;
     }
     MOZ_ASSERT_UNREACHABLE("Unknown side");
     return mBorderTopColor;
   }
 
-  const mozilla::StyleColor& BorderColorFor(mozilla::Side aSide) const {
+  const mozilla::StyleComplexColor& BorderColorFor(mozilla::Side aSide) const {
     switch (aSide) {
       case mozilla::eSideTop:
         return mBorderTopColor;
       case mozilla::eSideRight:
         return mBorderRightColor;
       case mozilla::eSideBottom:
         return mBorderBottomColor;
       case mozilla::eSideLeft:
         return mBorderLeftColor;
     }
     MOZ_ASSERT_UNREACHABLE("Unknown side");
     return mBorderTopColor;
   }
 
-  static mozilla::StyleColor nsStyleBorder::*BorderColorFieldFor(
+  static mozilla::StyleComplexColor nsStyleBorder::*BorderColorFieldFor(
       mozilla::Side aSide) {
     switch (aSide) {
       case mozilla::eSideTop:
         return &nsStyleBorder::mBorderTopColor;
       case mozilla::eSideRight:
         return &nsStyleBorder::mBorderRightColor;
       case mozilla::eSideBottom:
         return &nsStyleBorder::mBorderBottomColor;
@@ -1050,17 +1050,17 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
 
   // This is the specified value of outline-width, but with length values
   // computed to absolute.  mActualOutlineWidth stores the outline-width
   // value used by layout.  (We must store mOutlineWidth for the same
   // style struct resolution reasons that we do nsStyleBorder::mBorder;
   // see that field's comment.)
   nscoord mOutlineWidth;
   nscoord mOutlineOffset;
-  mozilla::StyleColor mOutlineColor;
+  mozilla::StyleComplexColor mOutlineColor;
   mozilla::StyleOutlineStyle mOutlineStyle;
 
   nscoord GetOutlineWidth() const { return mActualOutlineWidth; }
 
   bool ShouldPaintOutline() const {
     if (mOutlineStyle.IsAuto()) {
       return true;
     }
@@ -1435,17 +1435,17 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
 
   nsStyleTextOverflow mTextOverflow;  // enum, string
 
   mozilla::StyleTextDecorationLine mTextDecorationLine;
   uint8_t mTextDecorationStyle;  // NS_STYLE_TEXT_DECORATION_STYLE_*
   uint8_t mUnicodeBidi;          // NS_STYLE_UNICODE_BIDI_*
   nscoord mInitialLetterSink;    // 0 means normal
   float mInitialLetterSize;      // 0.0f means normal
-  mozilla::StyleColor mTextDecorationColor;
+  mozilla::StyleComplexColor mTextDecorationColor;
 };
 
 struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText {
   explicit nsStyleText(const mozilla::dom::Document&);
   nsStyleText(const nsStyleText& aOther);
   ~nsStyleText();
   void TriggerImageLoads(mozilla::dom::Document&, const nsStyleText*) {}
   const static bool kHasTriggerImageLoads = false;
@@ -1468,19 +1468,19 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
   uint8_t mRubyPosition;        // NS_STYLE_RUBY_POSITION_*
   uint8_t mTextSizeAdjust;      // NS_STYLE_TEXT_SIZE_ADJUST_*
   uint8_t mTextCombineUpright;  // NS_STYLE_TEXT_COMBINE_UPRIGHT_*
   uint8_t
       mControlCharacterVisibility;  // NS_STYLE_CONTROL_CHARACTER_VISIBILITY_*
   uint8_t mTextEmphasisPosition;    // NS_STYLE_TEXT_EMPHASIS_POSITION_*
   uint8_t mTextEmphasisStyle;       // NS_STYLE_TEXT_EMPHASIS_STYLE_*
   mozilla::StyleTextRendering mTextRendering;
-  mozilla::StyleColor mTextEmphasisColor;
-  mozilla::StyleColor mWebkitTextFillColor;
-  mozilla::StyleColor mWebkitTextStrokeColor;
+  mozilla::StyleComplexColor mTextEmphasisColor;
+  mozilla::StyleComplexColor mWebkitTextFillColor;
+  mozilla::StyleComplexColor mWebkitTextStrokeColor;
 
   mozilla::StyleNonNegativeLengthOrNumber mMozTabSize;
   mozilla::LengthPercentage mWordSpacing;
   mozilla::StyleLetterSpacing mLetterSpacing;
   mozilla::StyleLineHeight mLineHeight;
   mozilla::LengthPercentage mTextIndent;
   nscoord mWebkitTextStrokeWidth;  // coord
 
@@ -2559,23 +2559,26 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
 
   mozilla::StyleUserInput mUserInput;
   mozilla::StyleUserModify mUserModify;  // (modify-content)
   mozilla::StyleUserFocus mUserFocus;    // (auto-select)
   uint8_t mPointerEvents;                // NS_STYLE_POINTER_EVENTS_*
 
   mozilla::StyleCursorKind mCursor;
   nsTArray<nsCursorImage> mCursorImages;  // images and coords
-
-  mozilla::StyleColorOrAuto mCaretColor;
-  mozilla::StyleScrollbarColor mScrollbarColor;
+  mozilla::StyleComplexColor mCaretColor;
+
+  mozilla::StyleComplexColor mScrollbarFaceColor;
+  mozilla::StyleComplexColor mScrollbarTrackColor;
 
   inline uint8_t GetEffectivePointerEvents(nsIFrame* aFrame) const;
 
-  bool HasCustomScrollbars() const { return !mScrollbarColor.IsAuto(); }
+  bool HasCustomScrollbars() const {
+    return !mScrollbarFaceColor.IsAuto() || !mScrollbarTrackColor.IsAuto();
+  }
 };
 
 struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleXUL {
   explicit nsStyleXUL(const mozilla::dom::Document&);
   nsStyleXUL(const nsStyleXUL& aSource);
   ~nsStyleXUL();
   void TriggerImageLoads(mozilla::dom::Document&, const nsStyleXUL*) {}
   const static bool kHasTriggerImageLoads = false;
@@ -2605,17 +2608,17 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
   static const uint32_t kMaxColumnCount = 1000;
 
   // This represents the value of column-count: auto.
   static const uint32_t kColumnCountAuto = 0;
 
   uint32_t mColumnCount = kColumnCountAuto;
   nsStyleCoord mColumnWidth;  // coord, auto
 
-  mozilla::StyleColor mColumnRuleColor;
+  mozilla::StyleComplexColor mColumnRuleColor;
   mozilla::StyleBorderStyle mColumnRuleStyle;  // StyleborderStyle::*
   mozilla::StyleColumnFill mColumnFill = mozilla::StyleColumnFill::Balance;
   mozilla::StyleColumnSpan mColumnSpan = mozilla::StyleColumnSpan::None;
 
   nscoord GetComputedColumnRuleWidth() const {
     return (IsVisibleBorderStyle(mColumnRuleStyle) ? mColumnRuleWidth : 0);
   }
 
@@ -2659,69 +2662,69 @@ class nsStyleSVGPaint {
   nsStyleSVGPaint(const nsStyleSVGPaint& aSource);
   ~nsStyleSVGPaint();
 
   nsStyleSVGPaint& operator=(const nsStyleSVGPaint& aOther);
 
   nsStyleSVGPaintType Type() const { return mType; }
 
   void SetNone();
-  void SetColor(mozilla::StyleColor aColor);
+  void SetColor(mozilla::StyleComplexColor aColor);
   void SetPaintServer(mozilla::css::URLValue* aPaintServer,
                       nsStyleSVGFallbackType aFallbackType,
-                      mozilla::StyleColor aFallbackColor);
+                      mozilla::StyleComplexColor aFallbackColor);
   void SetPaintServer(mozilla::css::URLValue* aPaintServer) {
     SetPaintServer(aPaintServer, eStyleSVGFallbackType_NotSet,
-                   mozilla::StyleColor::Black());
+                   mozilla::StyleComplexColor::Black());
   }
   void SetContextValue(nsStyleSVGPaintType aType,
                        nsStyleSVGFallbackType aFallbackType,
-                       mozilla::StyleColor aFallbackColor);
+                       mozilla::StyleComplexColor aFallbackColor);
   void SetContextValue(nsStyleSVGPaintType aType) {
     SetContextValue(aType, eStyleSVGFallbackType_NotSet,
-                    mozilla::StyleColor::Black());
+                    mozilla::StyleComplexColor::Black());
   }
 
   nscolor GetColor(mozilla::ComputedStyle* aComputedStyle) const {
     MOZ_ASSERT(mType == eStyleSVGPaintType_Color);
-    return mPaint.mColor.CalcColor(*aComputedStyle);
+    return mPaint.mColor.CalcColor(aComputedStyle);
   }
 
   mozilla::css::URLValue* GetPaintServer() const {
     MOZ_ASSERT(mType == eStyleSVGPaintType_Server);
     return mPaint.mPaintServer;
   }
 
   nsStyleSVGFallbackType GetFallbackType() const { return mFallbackType; }
 
   nscolor GetFallbackColor(mozilla::ComputedStyle* aComputedStyle) const {
     MOZ_ASSERT(mType == eStyleSVGPaintType_Server ||
                mType == eStyleSVGPaintType_ContextFill ||
                mType == eStyleSVGPaintType_ContextStroke);
-    return mFallbackColor.CalcColor(*aComputedStyle);
+    return mFallbackColor.CalcColor(aComputedStyle);
   }
 
   bool operator==(const nsStyleSVGPaint& aOther) const;
   bool operator!=(const nsStyleSVGPaint& aOther) const {
     return !(*this == aOther);
   }
 
  private:
   void Reset();
   void Assign(const nsStyleSVGPaint& aOther);
 
   union ColorOrPaintServer {
-    mozilla::StyleColor mColor;
+    mozilla::StyleComplexColor mColor;
     mozilla::css::URLValue* mPaintServer;
-    explicit ColorOrPaintServer(mozilla::StyleColor c) : mColor(c) {}
+    explicit ColorOrPaintServer(mozilla::StyleComplexColor c) : mColor(c) {}
   };
   ColorOrPaintServer mPaint;
   nsStyleSVGPaintType mType;
   nsStyleSVGFallbackType mFallbackType;
-  mozilla::StyleColor mFallbackColor;
+  mozilla::StyleComplexColor mFallbackColor;
 };
 
 struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleSVG {
   explicit nsStyleSVG(const mozilla::dom::Document&);
   nsStyleSVG(const nsStyleSVG& aSource);
   ~nsStyleSVG();
   void TriggerImageLoads(mozilla::dom::Document&, const nsStyleSVG*) {}
   const static bool kHasTriggerImageLoads = false;
@@ -2892,19 +2895,19 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
   bool HasMask() const;
 
   bool HasNonScalingStroke() const {
     return mVectorEffect == NS_STYLE_VECTOR_EFFECT_NON_SCALING_STROKE;
   }
 
   nsStyleImageLayers mMask;
   mozilla::StyleShapeSource mClipPath;
-  mozilla::StyleColor mStopColor;
-  mozilla::StyleColor mFloodColor;
-  mozilla::StyleColor mLightingColor;
+  mozilla::StyleComplexColor mStopColor;
+  mozilla::StyleComplexColor mFloodColor;
+  mozilla::StyleComplexColor mLightingColor;
 
   float mStopOpacity;
   float mFloodOpacity;
 
   uint8_t mDominantBaseline;  // NS_STYLE_DOMINANT_BASELINE_*
   uint8_t mVectorEffect;      // NS_STYLE_VECTOR_EFFECT_*
   uint8_t mMaskType;          // NS_STYLE_MASK_TYPE_*
 };
--- a/layout/xul/nsTextBoxFrame.cpp
+++ b/layout/xul/nsTextBoxFrame.cpp
@@ -388,17 +388,17 @@ void nsTextBoxFrame::DrawText(gfxContext
     const nsStyleTextReset* styleText = context->StyleTextReset();
 
     if (decorMask &
         styleText->mTextDecorationLine) {  // a decoration defined here
       nscolor color;
       if (aOverrideColor) {
         color = *aOverrideColor;
       } else {
-        color = styleText->mTextDecorationColor.CalcColor(*context);
+        color = styleText->mTextDecorationColor.CalcColor(context);
       }
       uint8_t style = styleText->mTextDecorationStyle;
 
       if (StyleTextDecorationLine_UNDERLINE & decorMask &
           styleText->mTextDecorationLine) {
         underColor = color;
         underStyle = style;
         // TODO(emilio): Could add `operator~` or `remove()` to cbindgen.
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -2992,17 +2992,17 @@ ImgDrawResult nsTreeBodyFrame::PaintCell
                     twistyContext);
 
       nsMargin twistyMargin;
       twistyContext->StyleMargin()->GetMargin(twistyMargin);
       twistyRect.Inflate(twistyMargin);
 
       const nsStyleBorder* borderStyle = lineContext->StyleBorder();
       // Resolve currentcolor values against the treeline context
-      nscolor color = borderStyle->mBorderLeftColor.CalcColor(*lineContext);
+      nscolor color = borderStyle->mBorderLeftColor.CalcColor(lineContext);
       ColorPattern colorPatt(ToDeviceColor(color));
 
       StyleBorderStyle style = borderStyle->GetBorderStyle(eSideLeft);
       StrokeOptions strokeOptions;
       nsLayoutUtils::InitDashPattern(strokeOptions, style);
 
       nscoord srcX = currX + twistyRect.width - mIndentation / 2;
       nscoord lineY = (aRowIndex - mTopRowIndex) * mRowHeight + aPt.y;
--- a/servo/components/style/gecko_bindings/sugar/mod.rs
+++ b/servo/components/style/gecko_bindings/sugar/mod.rs
@@ -10,8 +10,9 @@ mod ns_css_shadow_array;
 mod ns_css_shadow_item;
 pub mod ns_css_value;
 mod ns_style_auto_array;
 pub mod ns_style_coord;
 mod ns_t_array;
 pub mod origin_flags;
 pub mod ownership;
 pub mod refptr;
+mod style_complex_color;
new file mode 100644
--- /dev/null
+++ b/servo/components/style/gecko_bindings/sugar/style_complex_color.rs
@@ -0,0 +1,111 @@
+/* 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 https://mozilla.org/MPL/2.0/. */
+
+//! Rust helpers to interact with Gecko's StyleComplexColor.
+
+use crate::gecko::values::{convert_nscolor_to_rgba, convert_rgba_to_nscolor};
+use crate::gecko_bindings::structs::StyleComplexColor;
+use crate::gecko_bindings::structs::StyleComplexColor_Tag as Tag;
+use crate::values::computed::{Color as ComputedColor, ColorOrAuto, RGBAColor as ComputedRGBA};
+use crate::values::generics::color::{
+    Color as GenericColor, ColorOrAuto as GenericColorOrAuto, ComplexColorRatios,
+};
+
+impl StyleComplexColor {
+    /// Create a `StyleComplexColor` value that represents `currentColor`.
+    pub fn current_color() -> Self {
+        StyleComplexColor {
+            mColor: 0,
+            mBgRatio: 0.,
+            mFgRatio: 1.,
+            mTag: Tag::eForeground,
+        }
+    }
+
+    /// Create a `StyleComplexColor` value that represents `auto`.
+    pub fn auto() -> Self {
+        StyleComplexColor {
+            mColor: 0,
+            mBgRatio: 0.,
+            mFgRatio: 1.,
+            mTag: Tag::eAuto,
+        }
+    }
+}
+
+impl From<ComputedRGBA> for StyleComplexColor {
+    fn from(other: ComputedRGBA) -> Self {
+        StyleComplexColor {
+            mColor: convert_rgba_to_nscolor(&other),
+            mBgRatio: 1.,
+            mFgRatio: 0.,
+            mTag: Tag::eNumeric,
+        }
+    }
+}
+
+impl From<ComputedColor> for StyleComplexColor {
+    fn from(other: ComputedColor) -> Self {
+        match other {
+            GenericColor::Numeric(color) => color.into(),
+            GenericColor::Foreground => Self::current_color(),
+            GenericColor::Complex(color, ratios) => {
+                debug_assert!(ratios != ComplexColorRatios::NUMERIC);
+                debug_assert!(ratios != ComplexColorRatios::FOREGROUND);
+                StyleComplexColor {
+                    mColor: convert_rgba_to_nscolor(&color).into(),
+                    mBgRatio: ratios.bg,
+                    mFgRatio: ratios.fg,
+                    mTag: Tag::eComplex,
+                }
+            },
+        }
+    }
+}
+
+impl From<StyleComplexColor> for ComputedColor {
+    fn from(other: StyleComplexColor) -> Self {
+        match other.mTag {
+            Tag::eNumeric => {
+                debug_assert!(other.mBgRatio == 1. && other.mFgRatio == 0.);
+                GenericColor::Numeric(convert_nscolor_to_rgba(other.mColor))
+            },
+            Tag::eForeground => {
+                debug_assert!(other.mBgRatio == 0. && other.mFgRatio == 1.);
+                GenericColor::Foreground
+            },
+            Tag::eComplex => {
+                debug_assert!(other.mBgRatio != 1. || other.mFgRatio != 0.);
+                debug_assert!(other.mBgRatio != 0. || other.mFgRatio != 1.);
+                GenericColor::Complex(
+                    convert_nscolor_to_rgba(other.mColor),
+                    ComplexColorRatios {
+                        bg: other.mBgRatio,
+                        fg: other.mFgRatio,
+                    },
+                )
+            },
+            Tag::eAuto => unreachable!("Unsupport StyleComplexColor with tag eAuto"),
+        }
+    }
+}
+
+impl From<ColorOrAuto> for StyleComplexColor {
+    fn from(other: ColorOrAuto) -> Self {
+        match other {
+            GenericColorOrAuto::Color(color) => color.into(),
+            GenericColorOrAuto::Auto => StyleComplexColor::auto(),
+        }
+    }
+}
+
+impl From<StyleComplexColor> for ColorOrAuto {
+    fn from(other: StyleComplexColor) -> Self {
+        if other.mTag != Tag::eAuto {
+            GenericColorOrAuto::Color(other.into())
+        } else {
+            GenericColorOrAuto::Auto
+        }
+    }
+}
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -392,16 +392,44 @@ def set_gecko_property(ffi_name, expr):
             % if keyword.gecko_inexhaustive:
             _ => panic!("Found unexpected value in style struct for ${ident} property"),
             % endif
         }
         % endif
     }
 </%def>
 
+<%def name="impl_color_setter(ident, gecko_ffi_name)">
+    #[allow(unreachable_code)]
+    #[allow(non_snake_case)]
+    pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
+        ${set_gecko_property(gecko_ffi_name, "v.into()")}
+    }
+</%def>
+
+<%def name="impl_color_copy(ident, gecko_ffi_name)">
+    #[allow(non_snake_case)]
+    pub fn copy_${ident}_from(&mut self, other: &Self) {
+        let color = ${get_gecko_property(gecko_ffi_name, self_param = "other")};
+        ${set_gecko_property(gecko_ffi_name, "color")};
+    }
+
+    #[allow(non_snake_case)]
+    pub fn reset_${ident}(&mut self, other: &Self) {
+        self.copy_${ident}_from(other)
+    }
+</%def>
+
+<%def name="impl_color_clone(ident, gecko_ffi_name)">
+    #[allow(non_snake_case)]
+    pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
+        ${get_gecko_property(gecko_ffi_name)}.into()
+    }
+</%def>
+
 <%def name="impl_keyword(ident, gecko_ffi_name, keyword, cast_type='u8', **kwargs)">
 <%call expr="impl_keyword_setter(ident, gecko_ffi_name, keyword, cast_type, **kwargs)"></%call>
 <%call expr="impl_simple_copy(ident, gecko_ffi_name, **kwargs)"></%call>
 <%call expr="impl_keyword_clone(ident, gecko_ffi_name, keyword, cast_type)"></%call>
 </%def>
 
 <%def name="impl_simple(ident, gecko_ffi_name)">
 <%call expr="impl_simple_setter(ident, gecko_ffi_name)"></%call>
@@ -416,16 +444,22 @@ def set_gecko_property(ffi_name, expr):
     }
     <%call expr="impl_simple_copy(ident, gecko_ffi_name)"></%call>
     #[allow(non_snake_case)]
     pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
         Au(self.gecko.${gecko_ffi_name}).into()
     }
 </%def>
 
+<%def name="impl_color(ident, gecko_ffi_name)">
+<%call expr="impl_color_setter(ident, gecko_ffi_name)"></%call>
+<%call expr="impl_color_copy(ident, gecko_ffi_name)"></%call>
+<%call expr="impl_color_clone(ident, gecko_ffi_name)"></%call>
+</%def>
+
 <%def name="impl_rgba_color(ident, gecko_ffi_name)">
     #[allow(non_snake_case)]
     pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
         ${set_gecko_property(gecko_ffi_name, "convert_rgba_to_nscolor(&v)")}
     }
     <%call expr="impl_simple_copy(ident, gecko_ffi_name)"></%call>
     #[allow(non_snake_case)]
     pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
@@ -1199,23 +1233,26 @@ impl Clone for ${style_struct.gecko_stru
 <%def name="impl_trait(style_struct_name, skip_longhands='')">
 <%
     style_struct = next(x for x in data.style_structs if x.name == style_struct_name)
     longhands = [x for x in style_struct.longhands
                 if not (skip_longhands == "*" or x.name in skip_longhands.split())]
 
     # Types used with predefined_type()-defined properties that we can auto-generate.
     predefined_types = {
+        "Color": impl_color,
+        "ColorOrAuto": impl_color,
         "length::LengthOrAuto": impl_style_coord,
         "length::LengthOrNormal": impl_style_coord,
         "length::NonNegativeLengthOrAuto": impl_style_coord,
         "length::NonNegativeLengthPercentageOrNormal": impl_style_coord,
         "Length": impl_absolute_length,
         "LengthOrNormal": impl_style_coord,
         "LengthPercentageOrAuto": impl_style_coord,
+        "MozListReversed": impl_simple,
         "MozScriptMinSize": impl_absolute_length,
         "RGBAColor": impl_rgba_color,
         "SVGLength": impl_svg_length,
         "SVGOpacity": impl_svg_opacity,
         "SVGPaint": impl_svg_paint,
         "SVGWidth": impl_svg_length,
         "Transform": impl_transform,
         "url::UrlOrNone": impl_css_url,
@@ -1337,17 +1374,17 @@ fn static_assert() {
         self.copy_border_${side.ident}_style_from(other);
     }
 
     #[inline]
     pub fn clone_border_${side.ident}_style(&self) -> BorderStyle {
         self.gecko.mBorderStyle[${side.index}]
     }
 
-    <% impl_simple("border_%s_color" % side.ident, "mBorder%sColor" % side.name) %>
+    <% impl_color("border_%s_color" % side.ident, "mBorder%sColor" % side.name) %>
 
     <% impl_non_negative_length("border_%s_width" % side.ident,
                                 "mComputedBorder.%s" % side.ident,
                                 inherit_from="mBorder.%s" % side.ident,
                                 round_to_pixels=True) %>
 
     pub fn border_${side.ident}_has_nonzero_width(&self) -> bool {
         self.gecko.mComputedBorder.${side.ident} != 0
@@ -4344,21 +4381,33 @@ clip-path
     }
 
     #[allow(non_snake_case)]
     pub fn reset__moz_context_properties(&mut self, other: &Self) {
         self.copy__moz_context_properties_from(other)
     }
 </%self:impl_trait>
 
-<%self:impl_trait style_struct_name="Color" skip_longhands="color">
-    ${impl_rgba_color("color", "mColor")}
+<%self:impl_trait style_struct_name="Color"
+                  skip_longhands="*">
+    pub fn set_color(&mut self, v: longhands::color::computed_value::T) {
+        let result = convert_rgba_to_nscolor(&v);
+        ${set_gecko_property("mColor", "result")}
+    }
+
+    <%call expr="impl_simple_copy('color', 'mColor')"></%call>
+
+    pub fn clone_color(&self) -> longhands::color::computed_value::T {
+        let color = ${get_gecko_property("mColor")} as u32;
+        convert_nscolor_to_rgba(color)
+    }
 </%self:impl_trait>
 
-<%self:impl_trait style_struct_name="InheritedUI" skip_longhands="cursor">
+<%self:impl_trait style_struct_name="InheritedUI"
+                  skip_longhands="cursor scrollbar-color">
     pub fn set_cursor(&mut self, v: longhands::cursor::computed_value::T) {
         self.gecko.mCursor = v.keyword;
         unsafe {
             Gecko_SetCursorArrayLength(&mut self.gecko, v.images.len());
         }
         for i in 0..v.images.len() {
             unsafe {
                 Gecko_SetCursorImageValue(
@@ -4410,16 +4459,58 @@ clip-path
                     None
                 };
 
             CursorImage { url, hotspot }
         }).collect::<Vec<_>>().into_boxed_slice();
 
         longhands::cursor::computed_value::T { images, keyword }
     }
+
+    pub fn set_scrollbar_color(&mut self, v: longhands::scrollbar_color::computed_value::T) {
+        use crate::gecko_bindings::structs::StyleComplexColor;
+        use crate::values::generics::ui::ScrollbarColor;
+        match v {
+            ScrollbarColor::Auto => {
+                self.gecko.mScrollbarFaceColor = StyleComplexColor::auto();
+                self.gecko.mScrollbarTrackColor = StyleComplexColor::auto();
+            }
+            ScrollbarColor::Colors { thumb, track } => {
+                self.gecko.mScrollbarFaceColor = thumb.into();
+                self.gecko.mScrollbarTrackColor = track.into();
+            }
+        }
+    }
+
+    pub fn copy_scrollbar_color_from(&mut self, other: &Self) {
+        self.gecko.mScrollbarFaceColor = other.gecko.mScrollbarFaceColor;
+        self.gecko.mScrollbarTrackColor = other.gecko.mScrollbarTrackColor;
+    }
+
+    pub fn reset_scrollbar_color(&mut self, other: &Self) {
+        self.copy_scrollbar_color_from(other);
+    }
+
+    pub fn clone_scrollbar_color(&self) -> longhands::scrollbar_color::computed_value::T {
+        use crate::gecko_bindings::structs::StyleComplexColor_Tag as Tag;
+        use crate::values::generics::ui::ScrollbarColor;
+        debug_assert!(
+            (self.gecko.mScrollbarFaceColor.mTag == Tag::eAuto) ==
+            (self.gecko.mScrollbarTrackColor.mTag == Tag::eAuto),
+            "Whether the two colors are `auto` should match",
+        );
+        if self.gecko.mScrollbarFaceColor.mTag == Tag::eAuto {
+            ScrollbarColor::Auto
+        } else {
+            ScrollbarColor::Colors {
+                thumb: self.gecko.mScrollbarFaceColor.into(),
+                track: self.gecko.mScrollbarTrackColor.into(),
+            }
+        }
+    }
 </%self:impl_trait>
 
 <%self:impl_trait style_struct_name="Column"
                   skip_longhands="column-count column-rule-width column-rule-style">
 
     #[allow(unused_unsafe)]
     pub fn set_column_count(&mut self, v: longhands::column_count::computed_value::T) {
         use crate::gecko_bindings::structs::{nsStyleColumn_kColumnCountAuto, nsStyleColumn_kMaxColumnCount};
--- a/servo/components/style/properties/properties.mako.rs
+++ b/servo/components/style/properties/properties.mako.rs
@@ -1288,17 +1288,17 @@ impl LonghandId {
         )
     }
 
     /// Whether computed values of this property lossily convert any complex
     /// colors into RGBA colors.
     ///
     /// In Gecko, there are some properties still that compute currentcolor
     /// down to an RGBA color at computed value time, instead of as
-    /// `StyleColor`s. For these properties, we must return `false`,
+    /// `StyleComplexColor`s. For these properties, we must return `false`,
     /// so that we correctly avoid caching style data in the rule tree.
     pub fn stores_complex_colors_lossily(&self) -> bool {
         % if product == "gecko":
         matches!(*self,
             % for property in data.longhands:
             % if property.predefined_type == "RGBAColor":
             LonghandId::${property.camel_case} |
             % endif
--- a/servo/components/style/values/animated/color.rs
+++ b/servo/components/style/values/animated/color.rs
@@ -95,80 +95,80 @@ impl ComputeSquaredDistance for RGBA {
 
 /// An animated value for `<color>`.
 pub type Color = GenericColor<RGBA>;
 
 impl Color {
     fn effective_intermediate_rgba(&self) -> RGBA {
         match *self {
             GenericColor::Numeric(color) => color,
-            GenericColor::CurrentColor => RGBA::transparent(),
-            GenericColor::Complex { color, ratios } => RGBA {
+            GenericColor::Foreground => RGBA::transparent(),
+            GenericColor::Complex(color, ratios) => RGBA {
                 alpha: color.alpha * ratios.bg,
                 ..color.clone()
             },
         }
     }
 
     fn effective_ratios(&self) -> ComplexColorRatios {
         match *self {
             GenericColor::Numeric(..) => ComplexColorRatios::NUMERIC,
-            GenericColor::CurrentColor => ComplexColorRatios::CURRENT_COLOR,
-            GenericColor::Complex { ratios, .. } => ratios,
+            GenericColor::Foreground => ComplexColorRatios::FOREGROUND,
+            GenericColor::Complex(.., ratios) => ratios,
         }
     }
 }
 
 impl Animate for Color {
     #[inline]
     fn animate(&self, other: &Self, procedure: Procedure) -> Result<Self, ()> {
         use self::GenericColor::*;
 
         // Common cases are interpolating between two numeric colors,
         // two currentcolors, and a numeric color and a currentcolor.
         let (this_weight, other_weight) = procedure.weights();
 
         Ok(match (*self, *other, procedure) {
             // Any interpolation of currentcolor with currentcolor returns currentcolor.
-            (CurrentColor, CurrentColor, Procedure::Interpolate { .. }) => CurrentColor,
+            (Foreground, Foreground, Procedure::Interpolate { .. }) => Foreground,
             // Animating two numeric colors.
             (Numeric(c1), Numeric(c2), _) => Numeric(c1.animate(&c2, procedure)?),
             // Combinations of numeric color and currentcolor
-            (CurrentColor, Numeric(color), _) => Self::with_ratios(
+            (Foreground, Numeric(color), _) => Self::with_ratios(
                 color,
                 ComplexColorRatios {
                     bg: other_weight as f32,
                     fg: this_weight as f32,
                 },
             ),
-            (Numeric(color), CurrentColor, _) => Self::with_ratios(
+            (Numeric(color), Foreground, _) => Self::with_ratios(
                 color,
                 ComplexColorRatios {
                     bg: this_weight as f32,
                     fg: other_weight as f32,
                 },
             ),
 
             // Any other animation of currentcolor with currentcolor.
-            (CurrentColor, CurrentColor, _) => Self::with_ratios(
+            (Foreground, Foreground, _) => Self::with_ratios(
                 RGBA::transparent(),
                 ComplexColorRatios {
                     bg: 0.,
                     fg: (this_weight + other_weight) as f32,
                 },
             ),
 
             // Defer to complex calculations
             _ => {
                 // Compute the "scaled" contribution for `color`.
                 fn scaled_rgba(color: &Color) -> RGBA {
                     match *color {
                         GenericColor::Numeric(color) => color,
-                        GenericColor::CurrentColor => RGBA::transparent(),
-                        GenericColor::Complex { color, ratios } => RGBA {
+                        GenericColor::Foreground => RGBA::transparent(),
+                        GenericColor::Complex(color, ratios) => RGBA {
                             red: color.red * ratios.bg,
                             green: color.green * ratios.bg,
                             blue: color.blue * ratios.bg,
                             alpha: color.alpha * ratios.bg,
                         },
                     }
                 }
 
@@ -231,19 +231,19 @@ impl Animate for Color {
 
 impl ComputeSquaredDistance for Color {
     #[inline]
     fn compute_squared_distance(&self, other: &Self) -> Result<SquaredDistance, ()> {
         use self::GenericColor::*;
 
         // All comments from the Animate impl also applies here.
         Ok(match (*self, *other) {
-            (CurrentColor, CurrentColor) => SquaredDistance::from_sqrt(0.),
+            (Foreground, Foreground) => SquaredDistance::from_sqrt(0.),
             (Numeric(c1), Numeric(c2)) => c1.compute_squared_distance(&c2)?,
-            (CurrentColor, Numeric(color)) | (Numeric(color), CurrentColor) => {
+            (Foreground, Numeric(color)) | (Numeric(color), Foreground) => {
                 // `computed_squared_distance` is symmetric.
                 color.compute_squared_distance(&RGBA::transparent())? +
                     SquaredDistance::from_sqrt(1.)
             },
             (_, _) => {
                 let self_color = self.effective_intermediate_rgba();
                 let other_color = other.effective_intermediate_rgba();
                 let self_ratios = self.effective_ratios();
--- a/servo/components/style/values/computed/color.rs
+++ b/servo/components/style/values/computed/color.rs
@@ -28,18 +28,18 @@ impl Color {
 
     /// Combine this complex color with the given foreground color into
     /// a numeric RGBA color. It currently uses linear blending.
     pub fn to_rgba(&self, fg_color: RGBA) -> RGBA {
         let (color, ratios) = match *self {
             // Common cases that the complex color is either pure numeric
             // color or pure currentcolor.
             GenericColor::Numeric(color) => return color,
-            GenericColor::CurrentColor => return fg_color,
-            GenericColor::Complex { color, ratios } => (color, ratios),
+            GenericColor::Foreground => return fg_color,
+            GenericColor::Complex(color, ratios) => (color, ratios),
         };
 
         // For the more complicated case that the alpha value differs,
         // we use the following formula to compute the components:
         // alpha = self_alpha * bg_ratio + fg_alpha * fg_ratio
         // color = (self_color * self_alpha * bg_ratio +
         //          fg_color * fg_alpha * fg_ratio) / alpha
 
@@ -71,17 +71,17 @@ impl Color {
 
 impl ToCss for Color {
     fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
     where
         W: fmt::Write,
     {
         match *self {
             GenericColor::Numeric(color) => color.to_css(dest),
-            GenericColor::CurrentColor => CSSParserColor::CurrentColor.to_css(dest),
+            GenericColor::Foreground => CSSParserColor::CurrentColor.to_css(dest),
             _ => Ok(()),
         }
     }
 }
 
 impl ToAnimatedValue for RGBA {
     type AnimatedValue = AnimatedRGBA;
 
--- a/servo/components/style/values/computed/ui.rs
+++ b/servo/components/style/values/computed/ui.rs
@@ -14,9 +14,9 @@ pub use crate::values::specified::ui::{M
 
 /// A computed value for the `cursor` property.
 pub type Cursor = generics::Cursor<CursorImage>;
 
 /// A computed value for item of `image cursors`.
 pub type CursorImage = generics::CursorImage<ComputedImageUrl, Number>;
 
 /// A computed value for `scrollbar-color` property.
-pub type ScrollbarColor = generics::GenericScrollbarColor<Color>;
+pub type ScrollbarColor = generics::ScrollbarColor<Color>;
--- a/servo/components/style/values/generics/color.rs
+++ b/servo/components/style/values/generics/color.rs
@@ -2,84 +2,75 @@
  * 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 color properties.
 
 /// Ratios representing the contribution of color and currentcolor to
 /// the final color value.
 #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, ToShmem)]
-#[repr(C)]
 pub struct ComplexColorRatios {
     /// Numeric color contribution.
     pub bg: f32,
-    /// currentcolor contribution.
+    /// Foreground color, aka currentcolor, contribution.
     pub fg: f32,
 }
 
 impl ComplexColorRatios {
     /// Ratios representing a `Numeric` color.
     pub const NUMERIC: ComplexColorRatios = ComplexColorRatios { bg: 1., fg: 0. };
-    /// Ratios representing the `CurrentColor` color.
-    pub const CURRENT_COLOR: ComplexColorRatios = ComplexColorRatios { bg: 0., fg: 1. };
+    /// Ratios representing the `Foreground` color.
+    pub const FOREGROUND: ComplexColorRatios = ComplexColorRatios { bg: 0., fg: 1. };
 }
 
 /// This enum represents a combined color from a numeric color and
 /// the current foreground color (currentcolor keyword).
 #[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToAnimatedValue, ToShmem)]
-#[repr(C, u8)]
-pub enum GenericColor<RGBA> {
+pub enum Color<RGBA> {
     ///  Numeric RGBA color.
     Numeric(RGBA),
 
     /// The current foreground color.
-    CurrentColor,
+    Foreground,
 
     /// A linear combination of numeric color and currentcolor.
     /// The formula is: `color * ratios.bg + currentcolor * ratios.fg`.
-    Complex {
-        /// The actual numeric color.
-        color: RGBA,
-        /// The ratios of mixing between numeric and currentcolor.
-        ratios: ComplexColorRatios,
-    }
+    Complex(RGBA, ComplexColorRatios),
 }
 
-pub use self::GenericColor as Color;
-
 impl<RGBA> Color<RGBA> {
     /// Create a color based upon the specified ratios.
     pub fn with_ratios(color: RGBA, ratios: ComplexColorRatios) -> Self {
         if ratios == ComplexColorRatios::NUMERIC {
             Color::Numeric(color)
-        } else if ratios == ComplexColorRatios::CURRENT_COLOR {
-            Color::CurrentColor
+        } else if ratios == ComplexColorRatios::FOREGROUND {
+            Color::Foreground
         } else {
-            Color::Complex { color, ratios }
+            Color::Complex(color, ratios)
         }
     }
 
     /// Returns a numeric color representing the given RGBA value.
     pub fn rgba(color: RGBA) -> Self {
         Color::Numeric(color)
     }
 
     /// Returns a complex color value representing currentcolor.
     pub fn currentcolor() -> Self {
-        Color::CurrentColor
+        Color::Foreground
     }
 
     /// Whether it is a numeric color (no currentcolor component).
     pub fn is_numeric(&self) -> bool {
         matches!(*self, Color::Numeric(..))
     }
 
     /// Whether it is a currentcolor value (no numeric color component).
     pub fn is_currentcolor(&self) -> bool {
-        matches!(*self, Color::CurrentColor)
+        matches!(*self, Color::Foreground)
     }
 }
 
 impl<RGBA> From<RGBA> for Color<RGBA> {
     fn from(color: RGBA) -> Self {
         Self::rgba(color)
     }
 }
@@ -96,17 +87,14 @@ impl<RGBA> From<RGBA> for Color<RGBA> {
     Parse,
     SpecifiedValueInfo,
     ToAnimatedValue,
     ToAnimatedZero,
     ToComputedValue,
     ToCss,
     ToShmem,
 )]
-#[repr(C, u8)]
-pub enum GenericColorOrAuto<C> {
-    /// A `<color>`.
+pub enum ColorOrAuto<C> {
+    /// A `<color>
     Color(C),
     /// `auto`
     Auto,
 }
-
-pub use self::GenericColorOrAuto as ColorOrAuto;
--- a/servo/components/style/values/generics/ui.rs
+++ b/servo/components/style/values/generics/ui.rs
@@ -81,29 +81,26 @@ impl<ImageUrl: ToCss, Number: ToCss> ToC
     PartialEq,
     SpecifiedValueInfo,
     ToAnimatedValue,
     ToAnimatedZero,
     ToComputedValue,
     ToCss,
     ToShmem,
 )]
-#[repr(C, u8)]
-pub enum GenericScrollbarColor<Color> {
+pub enum ScrollbarColor<Color> {
     /// `auto`
     Auto,
     /// `<color>{2}`
     Colors {
         /// First `<color>`, for color of the scrollbar thumb.
         thumb: Color,
         /// Second `<color>`, for color of the scrollbar track.
         track: Color,
     },
 }
 
-pub use self::GenericScrollbarColor as ScrollbarColor;
-
 impl<Color> Default for ScrollbarColor<Color> {
     #[inline]
     fn default() -> Self {
         ScrollbarColor::Auto
     }
 }
--- a/servo/components/style/values/specified/color.rs
+++ b/servo/components/style/values/specified/color.rs
@@ -382,18 +382,18 @@ impl ToComputedValue for Color {
             }
         }
         result
     }
 
     fn from_computed_value(computed: &ComputedColor) -> Self {
         match *computed {
             GenericColor::Numeric(color) => Color::rgba(color),
-            GenericColor::CurrentColor => Color::currentcolor(),
-            GenericColor::Complex { .. } => Color::Complex(*computed),
+            GenericColor::Foreground => Color::currentcolor(),
+            GenericColor::Complex(..) => Color::Complex(*computed),
         }
     }
 }
 
 /// Specified color value, but resolved to just RGBA for computed value
 /// with value from color property at the same context.
 #[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
 pub struct RGBAColor(pub Color);
--- a/servo/ports/geckolib/cbindgen.toml
+++ b/servo/ports/geckolib/cbindgen.toml
@@ -101,19 +101,16 @@ include = [
   "RestyleHint",
   "TouchAction",
   "WillChangeBits",
   "TextDecorationLine",
   "MozListReversed",
   "Owned",
   "OwnedOrNull",
   "Strong",
-  "ScrollbarColor",
-  "Color",
-  "ColorOrAuto",
 ]
 item_types = ["enums", "structs", "typedefs", "functions"]
 renaming_overrides_prefixing = true
 
 # Prevent some renaming for Gecko types that cbindgen doesn't otherwise understand.
 [export.rename]
 "nscolor" = "nscolor"
 "nsAtom" = "nsAtom"
@@ -278,30 +275,8 @@ renaming_overrides_prefixing = true
 
 "Strong" = """
   already_AddRefed<GeckoType> Consume() {
     already_AddRefed<GeckoType> ret(const_cast<GeckoType*>(ptr));
     ptr = nullptr;
     return ret;
   }
 """
-
-"GenericColor" = """
-  static inline StyleGenericColor FromColor(nscolor);
-  static inline StyleGenericColor Black();
-  static inline StyleGenericColor White();
-  static inline StyleGenericColor Transparent();
-  bool MaybeTransparent() const;
-  /**
-   * Compute the final color, taking into account the foreground color from the
-   * frame's ComputedStyle.
-   */
-  nscolor CalcColor(const nsIFrame*) const;
-  /**
-   * Compute the final color, taking into account the foreground color from the
-   * style.
-   */
-  nscolor CalcColor(const ComputedStyle&) const;
-  /**
-   * Compute the final color, making the argument the foreground color.
-   */
-  nscolor CalcColor(nscolor) const;
-"""
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -2448,20 +2448,19 @@ nsNativeThemeCocoa::ScrollbarParams nsNa
   params.horizontal = aIsHorizontal;
   params.onDarkBackground = IsDarkBackground(aFrame);
   // Don't use custom scrollbars for overlay scrollbars since they are
   // generally good enough for use cases of custom scrollbars.
   if (!params.overlay) {
     ComputedStyle* style = nsLayoutUtils::StyleForScrollbar(aFrame);
     const nsStyleUI* ui = style->StyleUI();
     if (ui->HasCustomScrollbars()) {
-      const auto& colors = ui->mScrollbarColor.AsColors();
       params.custom = true;
-      params.trackColor = colors.track.CalcColor(*style);
-      params.faceColor = colors.thumb.CalcColor(*style);
+      params.trackColor = ui->mScrollbarTrackColor.CalcColor(style);
+      params.faceColor = ui->mScrollbarFaceColor.CalcColor(style);
     }
   }
   return params;
 }
 
 void nsNativeThemeCocoa::DrawScrollbarThumb(CGContextRef cgContext, const CGRect& inBoxRect,
                                             ScrollbarParams aParams) {
   CGRect drawRect = inBoxRect;
@@ -4464,18 +4463,18 @@ nsITheme::Transparency nsNativeThemeCoco
     case StyleAppearance::ScrollbarSmall:
     case StyleAppearance::Scrollbar:
     case StyleAppearance::Scrollcorner: {
       // We don't use custom scrollbars when using overlay scrollbars.
       if (nsLookAndFeel::UseOverlayScrollbars()) {
         return eTransparent;
       }
       const nsStyleUI* ui = nsLayoutUtils::StyleForScrollbar(aFrame)->StyleUI();
-      if (!ui->mScrollbarColor.IsAuto() &&
-          ui->mScrollbarColor.AsColors().track.MaybeTransparent()) {
+      StyleComplexColor trackColor = ui->mScrollbarTrackColor;
+      if (!trackColor.IsAuto() && trackColor.MaybeTransparent()) {
         return eTransparent;
       }
       return eOpaque;
     }
 
     case StyleAppearance::Statusbar:
       // Knowing that scrollbars and statusbars are opaque improves
       // performance, because we create layers for them.
--- a/widget/windows/nsNativeThemeWin.cpp
+++ b/widget/windows/nsNativeThemeWin.cpp
@@ -2655,19 +2655,17 @@ nsITheme::ThemeGeometryType nsNativeThem
   }
 }
 
 nsITheme::Transparency nsNativeThemeWin::GetWidgetTransparency(
     nsIFrame* aFrame, StyleAppearance aAppearance) {
   if (IsWidgetScrollbarPart(aAppearance)) {
     ComputedStyle* style = nsLayoutUtils::StyleForScrollbar(aFrame);
     if (ShouldDrawCustomScrollbar(style)) {
-      auto* ui = style->StyleUI();
-      if (ui->mScrollbarColor.IsAuto() ||
-          ui->mScrollbarColor.AsColors().track.MaybeTransparent()) {
+      if (style->StyleUI()->mScrollbarTrackColor.MaybeTransparent()) {
         return eTransparent;
       }
       // DrawCustomScrollbarPart doesn't draw the track background for
       // widgets on it, and these widgets are thinner than the track,
       // so we need to return transparent for them.
       switch (aAppearance) {
         case StyleAppearance::ScrollbarthumbHorizontal:
         case StyleAppearance::ScrollbarthumbVertical:
@@ -4167,20 +4165,19 @@ nsresult nsNativeThemeWin::DrawCustomScr
   gfxFloat p2a = gfxFloat(aFrame->PresContext()->AppUnitsPerDevPixel());
   gfxRect clipRect = ThebesRect(
       LayoutDevicePixel::FromAppUnits(aClipRect, p2a).ToUnknownRect());
   ctx->Clip(clipRect);
   gfxRect rect =
       ThebesRect(LayoutDevicePixel::FromAppUnits(aRect, p2a).ToUnknownRect());
 
   const nsStyleUI* ui = aStyle->StyleUI();
-  auto* customColors =
-      ui->mScrollbarColor.IsAuto() ? nullptr : &ui->mScrollbarColor.AsColors();
-  nscolor trackColor = customColors ? customColors->track.CalcColor(*aStyle)
-                                    : NS_RGB(240, 240, 240);
+  nscolor trackColor = ui->mScrollbarTrackColor.IsAuto()
+                           ? NS_RGB(240, 240, 240)
+                           : ui->mScrollbarTrackColor.CalcColor(aStyle);
   switch (aAppearance) {
     case StyleAppearance::ScrollbarHorizontal:
     case StyleAppearance::ScrollbarVertical:
     case StyleAppearance::Scrollcorner: {
       ctx->SetColor(Color::FromABGR(trackColor));
       ctx->Rectangle(rect);
       ctx->Fill();
       return NS_OK;
@@ -4205,18 +4202,19 @@ nsresult nsNativeThemeWin::DrawCustomScr
       break;
     default:
       MOZ_ASSERT_UNREACHABLE("Unknown widget type");
   }
 
   switch (aAppearance) {
     case StyleAppearance::ScrollbarthumbVertical:
     case StyleAppearance::ScrollbarthumbHorizontal: {
-      nscolor faceColor = customColors ? customColors->thumb.CalcColor(*aStyle)
-                                       : NS_RGB(205, 205, 205);
+      nscolor faceColor = ui->mScrollbarFaceColor.IsAuto()
+                              ? NS_RGB(205, 205, 205)
+                              : ui->mScrollbarFaceColor.CalcColor(aStyle);
       faceColor = AdjustScrollbarFaceColor(faceColor, eventStates);
       ctx->SetColor(Color::FromABGR(faceColor));
       ctx->Rectangle(bgRect);
       ctx->Fill();
       break;
     }
     case StyleAppearance::ScrollbarbuttonUp:
     case StyleAppearance::ScrollbarbuttonDown: