Bug 1299741 part 11 - Change text-{emphasis,fill,stroke}-color to using StyleComplexColor. r=dbaron draft
authorXidorn Quan <me@upsuper.org>
Fri, 16 Sep 2016 14:40:45 +1000
changeset 415370 293aa61adaa091bb3d4350a4b86ec9cfbb40eb02
parent 415369 855783009cb8a8c800504299c53055634dbc66bd
child 415371 01224dc8a6d9ec613197bce78f6c0a43603242dc
push id29862
push userxquan@mozilla.com
push dateTue, 20 Sep 2016 08:44:59 +0000
reviewersdbaron
bugs1299741
milestone52.0a1
Bug 1299741 part 11 - Change text-{emphasis,fill,stroke}-color to using StyleComplexColor. r=dbaron MozReview-Commit-ID: 1MlgGAkdPn8
layout/generic/TextOverflow.cpp
layout/generic/nsTextFrame.cpp
layout/mathml/nsMathMLChar.cpp
layout/mathml/nsMathMLFrame.cpp
layout/mathml/nsMathMLmencloseFrame.cpp
layout/mathml/nsMathMLmfracFrame.cpp
layout/style/StyleAnimationValue.cpp
layout/style/nsCSSPropList.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsComputedDOMStyle.h
layout/style/nsRuleNode.cpp
layout/style/nsStyleContext.cpp
layout/style/nsStyleContext.h
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
--- a/layout/generic/TextOverflow.cpp
+++ b/layout/generic/TextOverflow.cpp
@@ -209,18 +209,18 @@ PaintTextShadowCallback(nsRenderingConte
   reinterpret_cast<nsDisplayTextOverflowMarker*>(aData)->
            PaintTextToContext(aCtx, aShadowOffset);
 }
 
 void
 nsDisplayTextOverflowMarker::Paint(nsDisplayListBuilder* aBuilder,
                                    nsRenderingContext*   aCtx)
 {
-  nsCSSPropertyID colorProp = mFrame->StyleContext()->GetTextFillColorProp();
-  nscolor foregroundColor = nsLayoutUtils::GetColor(mFrame, colorProp);
+  nscolor foregroundColor = nsLayoutUtils::
+    GetColor(mFrame, eCSSProperty__webkit_text_fill_color);
 
   // Paint the text-shadows for the overflow marker
   nsLayoutUtils::PaintTextShadow(mFrame, aCtx, mRect, mVisibleRect,
                                  foregroundColor, PaintTextShadowCallback,
                                  (void*)this);
   aCtx->ThebesContext()->SetColor(gfx::Color::FromABGR(foregroundColor));
   PaintTextToContext(aCtx, nsPoint(0, 0));
 }
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -327,17 +327,18 @@ public:
   nscolor GetTextColor();
 
   // SVG text has its own painting process, so we should never get its stroke
   // property from here.
   nscolor GetWebkitTextStrokeColor() {
     if (mFrame->IsSVGText()) {
       return 0;
     }
-    return mFrame->StyleContext()->GetTextStrokeColor();
+    return mFrame->StyleColor()->
+      CalcComplexColor(mFrame->StyleText()->mWebkitTextStrokeColor);
   }
   float GetWebkitTextStrokeWidth() {
     if (mFrame->IsSVGText()) {
       return 0.0f;
     }
     nscoord coord = mFrame->StyleText()->mWebkitTextStrokeWidth.GetCoordValue();
     return mFrame->PresContext()->AppUnitsToFloatDevPixels(coord);
   }
@@ -3702,18 +3703,17 @@ nsTextPaintStyle::GetTextColor()
       case eStyleSVGPaintType_Color:
         return nsLayoutUtils::GetColor(mFrame, eCSSProperty_fill);
       default:
         NS_ERROR("cannot resolve SVG paint to nscolor");
         return NS_RGBA(0, 0, 0, 255);
     }
   }
 
-  return nsLayoutUtils::GetColor(mFrame,
-                                 mFrame->StyleContext()->GetTextFillColorProp());
+  return nsLayoutUtils::GetColor(mFrame, eCSSProperty__webkit_text_fill_color);
 }
 
 bool
 nsTextPaintStyle::GetSelectionColors(nscolor* aForeColor,
                                      nscolor* aBackColor)
 {
   NS_ASSERTION(aForeColor, "aForeColor is null");
   NS_ASSERTION(aBackColor, "aBackColor is null");
@@ -3896,17 +3896,18 @@ nsTextPaintStyle::InitSelectionColorsAnd
     sc = mPresContext->StyleSet()->
       ProbePseudoElementStyle(selectionElement,
                               CSSPseudoElementType::mozSelection,
                               mFrame->StyleContext());
     // Use -moz-selection pseudo class.
     if (sc) {
       mSelectionBGColor =
         sc->GetVisitedDependentColor(eCSSProperty_background_color);
-      mSelectionTextColor = sc->GetVisitedDependentColor(sc->GetTextFillColorProp());
+      mSelectionTextColor =
+        sc->GetVisitedDependentColor(eCSSProperty__webkit_text_fill_color);
       mHasSelectionShadow =
         nsRuleNode::HasAuthorSpecifiedRules(sc,
                                             NS_AUTHOR_SPECIFIED_TEXT_SHADOW,
                                             true);
       if (mHasSelectionShadow) {
         mSelectionShadow = sc->StyleText()->mTextShadow;
       }
       return true;
@@ -3934,23 +3935,23 @@ nsTextPaintStyle::InitSelectionColorsAnd
   mSelectionTextColor =
     LookAndFeel::GetColor(LookAndFeel::eColorID_TextSelectForeground);
 
   if (mResolveColors) {
     // On MacOS X, we don't exchange text color and BG color.
     if (mSelectionTextColor == NS_DONT_CHANGE_COLOR) {
       nsCSSPropertyID property = mFrame->IsSVGText()
                                ? eCSSProperty_fill
-                               : mFrame->StyleContext()->GetTextFillColorProp();
+                               : eCSSProperty__webkit_text_fill_color;
       nscoord frameColor = mFrame->GetVisitedDependentColor(property);
       mSelectionTextColor = EnsureDifferentColors(frameColor, mSelectionBGColor);
     } else if (mSelectionTextColor == NS_CHANGE_COLOR_IF_SAME_AS_BG) {
       nsCSSPropertyID property = mFrame->IsSVGText()
                                ? eCSSProperty_fill
-                               : mFrame->StyleContext()->GetTextFillColorProp();
+                               : eCSSProperty__webkit_text_fill_color;
       nscolor frameColor = mFrame->GetVisitedDependentColor(property);
       if (frameColor == mSelectionBGColor) {
         mSelectionTextColor =
           LookAndFeel::GetColor(LookAndFeel::eColorID_TextSelectForegroundCustom);
       }
     } else {
       EnsureSufficientContrast(&mSelectionTextColor, &mSelectionBGColor);
     }
@@ -4947,19 +4948,21 @@ nsTextFrame::BuildDisplayList(nsDisplayL
                               const nsRect&           aDirtyRect,
                               const nsDisplayListSet& aLists)
 {
   if (!IsVisibleForPainting(aBuilder))
     return;
   
   DO_GLOBAL_REFLOW_COUNT_DSP("nsTextFrame");
 
-  nsStyleContext* sc = StyleContext();
-  bool isTextTransparent = (NS_GET_A(sc->GetTextFillColor()) == 0) &&
-                           (NS_GET_A(sc->GetTextStrokeColor()) == 0);
+  const nsStyleColor* sc = StyleColor();
+  const nsStyleText* st = StyleText();
+  bool isTextTransparent =
+    NS_GET_A(sc->CalcComplexColor(st->mWebkitTextFillColor)) == 0 &&
+    NS_GET_A(sc->CalcComplexColor(st->mWebkitTextStrokeColor)) == 0;
   Maybe<bool> isSelected;
   if (((GetStateBits() & TEXT_NO_RENDERED_GLYPHS) ||
        (isTextTransparent && !StyleText()->HasTextShadow())) &&
       aBuilder->IsForPainting() && !IsSVGText()) {
     isSelected.emplace(IsSelected());
     if (!isSelected.value()) {
       TextDecorations textDecs;
       GetTextDecorations(PresContext(), eResolvedColors, textDecs);
--- a/layout/mathml/nsMathMLChar.cpp
+++ b/layout/mathml/nsMathMLChar.cpp
@@ -2119,18 +2119,18 @@ nsMathMLChar::PaintForeground(nsPresCont
     // normal drawing if there is nothing special about this char
     // Set default context to the parent context
     styleContext = parentContext;
   }
 
   RefPtr<gfxContext> thebesContext = aRenderingContext.ThebesContext();
 
   // Set color ...
-  nsCSSPropertyID colorProp = styleContext->GetTextFillColorProp();
-  nscolor fgColor = styleContext->GetVisitedDependentColor(colorProp);
+  nscolor fgColor = styleContext->
+    GetVisitedDependentColor(eCSSProperty__webkit_text_fill_color);
   if (aIsSelected) {
     // get color to use for selection from the look&feel object
     fgColor = LookAndFeel::GetColor(LookAndFeel::eColorID_TextSelectForeground,
                                     fgColor);
   }
   thebesContext->SetColor(Color::FromABGR(fgColor));
   thebesContext->Save();
   nsRect r = mRect + aPt;
--- a/layout/mathml/nsMathMLFrame.cpp
+++ b/layout/mathml/nsMathMLFrame.cpp
@@ -360,19 +360,18 @@ void nsDisplayMathMLBar::Paint(nsDisplay
                                nsRenderingContext* aCtx)
 {
   // paint the bar with the current text color
   DrawTarget* drawTarget = aCtx->GetDrawTarget();
   Rect rect =
     NSRectToNonEmptySnappedRect(mRect + ToReferenceFrame(),
                                 mFrame->PresContext()->AppUnitsPerDevPixel(),
                                 *drawTarget);
-  nsCSSPropertyID colorProp = mFrame->StyleContext()->GetTextFillColorProp();
   ColorPattern color(ToDeviceColor(
-                                 mFrame->GetVisitedDependentColor(colorProp)));
+    mFrame->GetVisitedDependentColor(eCSSProperty__webkit_text_fill_color)));
   drawTarget->FillRect(rect, color);
 }
 
 void
 nsMathMLFrame::DisplayBar(nsDisplayListBuilder* aBuilder,
                           nsIFrame* aFrame, const nsRect& aRect,
                           const nsDisplayListSet& aLists) {
   if (!aFrame->StyleVisibility()->IsVisible() || aRect.IsEmpty())
--- a/layout/mathml/nsMathMLmencloseFrame.cpp
+++ b/layout/mathml/nsMathMLmencloseFrame.cpp
@@ -774,19 +774,18 @@ void nsDisplayNotation::Paint(nsDisplayL
   nsPresContext* presContext = mFrame->PresContext();
 
   Float strokeWidth = presContext->AppUnitsToGfxUnits(mThickness);
 
   Rect rect = NSRectToRect(mRect + ToReferenceFrame(),
                            presContext->AppUnitsPerDevPixel());
   rect.Deflate(strokeWidth / 2.f);
 
-  nsCSSPropertyID colorProp = mFrame->StyleContext()->GetTextFillColorProp();
   ColorPattern color(ToDeviceColor(
-                                 mFrame->GetVisitedDependentColor(colorProp)));
+    mFrame->GetVisitedDependentColor(eCSSProperty__webkit_text_fill_color)));
 
   StrokeOptions strokeOptions(strokeWidth);
 
   switch(mType)
   {
     case NOTATION_CIRCLE: {
       RefPtr<Path> ellipse =
         MakePathForEllipse(aDrawTarget, rect.Center(), rect.Size());
--- a/layout/mathml/nsMathMLmfracFrame.cpp
+++ b/layout/mathml/nsMathMLmfracFrame.cpp
@@ -623,22 +623,21 @@ void nsDisplayMathMLSlash::Paint(nsDispl
                                  nsRenderingContext* aCtx)
 {
   DrawTarget& aDrawTarget = *aCtx->GetDrawTarget();
 
   // get the gfxRect
   nsPresContext* presContext = mFrame->PresContext();
   Rect rect = NSRectToRect(mRect + ToReferenceFrame(),
                            presContext->AppUnitsPerDevPixel());
-  
-  nsCSSPropertyID colorProp = mFrame->StyleContext()->GetTextFillColorProp();
+
   ColorPattern color(ToDeviceColor(
-                                 mFrame->GetVisitedDependentColor(colorProp)));
- 
-  // draw the slash as a parallelogram 
+    mFrame->GetVisitedDependentColor(eCSSProperty__webkit_text_fill_color)));
+
+  // draw the slash as a parallelogram
   Point delta = Point(presContext->AppUnitsToGfxUnits(mThickness), 0);
   RefPtr<PathBuilder> builder = aDrawTarget.CreatePathBuilder();
   if (mRTL) {
     builder->MoveTo(rect.TopLeft());
     builder->LineTo(rect.TopLeft() + delta);
     builder->LineTo(rect.BottomRight());
     builder->LineTo(rect.BottomRight() - delta);
   } else {
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -3415,27 +3415,16 @@ template<typename T>
 inline const T&
 StyleDataAtOffset(const void* aStyleStruct, ptrdiff_t aOffset)
 {
   return *reinterpret_cast<const T*>(
     reinterpret_cast<const uint8_t*>(aStyleStruct) + aOffset);
 }
 
 static void
-SetCurrentOrActualColor(bool aIsForeground, nscolor aActualColor,
-                        StyleAnimationValue& aComputedValue)
-{
-  if (aIsForeground) {
-    aComputedValue.SetCurrentColorValue();
-  } else {
-    aComputedValue.SetColorValue(aActualColor);
-  }
-}
-
-static void
 ExtractBorderColor(nsStyleContext* aStyleContext, const void* aStyleBorder,
                    mozilla::css::Side aSide,
                    StyleAnimationValue& aComputedValue)
 {
   nscolor color;
   bool foreground;
   static_cast<const nsStyleBorder*>(aStyleBorder)->
     GetBorderColor(aSide, color, foreground);
@@ -3922,40 +3911,16 @@ StyleAnimationValue::ExtractComputedValu
         case eCSSProperty_text_decoration_style: {
           uint8_t decorationStyle =
             static_cast<const nsStyleTextReset*>(styleStruct)->
               GetDecorationStyle();
           aComputedValue.SetIntValue(decorationStyle, eUnit_Enumerated);
           break;
         }
 
-        case eCSSProperty_text_emphasis_color: {
-          auto styleText = static_cast<const nsStyleText*>(styleStruct);
-          SetCurrentOrActualColor(styleText->mTextEmphasisColorForeground,
-                                  styleText->mTextEmphasisColor,
-                                  aComputedValue);
-          break;
-        }
-
-        case eCSSProperty__webkit_text_fill_color: {
-          auto styleText = static_cast<const nsStyleText*>(styleStruct);
-          SetCurrentOrActualColor(styleText->mWebkitTextFillColorForeground,
-                                  styleText->mWebkitTextFillColor,
-                                  aComputedValue);
-          break;
-        }
-
-        case eCSSProperty__webkit_text_stroke_color: {
-          auto styleText = static_cast<const nsStyleText*>(styleStruct);
-          SetCurrentOrActualColor(styleText->mWebkitTextStrokeColorForeground,
-                                  styleText->mWebkitTextStrokeColor,
-                                  aComputedValue);
-          break;
-        }
-
         case eCSSProperty_border_spacing: {
           const nsStyleTableBorder *styleTableBorder =
             static_cast<const nsStyleTableBorder*>(styleStruct);
           nsAutoPtr<nsCSSValuePair> pair(new nsCSSValuePair);
           nscoordToCSSValue(styleTableBorder->mBorderSpacingCol, pair->mXValue);
           nscoordToCSSValue(styleTableBorder->mBorderSpacingRow, pair->mYValue);
           aComputedValue.SetAndAdoptCSSValuePairValue(pair.forget(),
                                                       eUnit_CSSValuePair);
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -3976,18 +3976,18 @@ CSS_PROP_TEXT(
     text-emphasis-color,
     text_emphasis_color,
     TextEmphasisColor,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED,
     "",
     VARIANT_HC,
     nullptr,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_Custom)
+    offsetof(nsStyleText, mTextEmphasisColor),
+    eStyleAnimType_ComplexColor)
 CSS_PROP_TEXT(
     text-emphasis-position,
     text_emphasis_position,
     TextEmphasisPosition,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_VALUE_PARSER_FUNCTION,
     "",
     0,
@@ -4012,17 +4012,17 @@ CSS_PROP_TEXT(
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE |
         CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
         CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED,
     "layout.css.prefixes.webkit",
     VARIANT_HC,
     nullptr,
     offsetof(nsStyleText, mWebkitTextFillColor),
-    eStyleAnimType_Custom)
+    eStyleAnimType_ComplexColor)
 CSS_PROP_TEXT(
     text-indent,
     text_indent,
     TextIndent,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_STORES_CALC |
         CSS_PROPERTY_UNITLESS_LENGTH_QUIRK |
         CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH,
@@ -4101,17 +4101,17 @@ CSS_PROP_TEXT(
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE |
         CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
         CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED,
     "layout.css.prefixes.webkit",
     VARIANT_HC,
     nullptr,
     offsetof(nsStyleText, mWebkitTextStrokeColor),
-    eStyleAnimType_Custom)
+    eStyleAnimType_ComplexColor)
 CSS_PROP_TEXT(
     -webkit-text-stroke-width,
     _webkit_text_stroke_width,
     WebkitTextStrokeWidth,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_VALUE_NONNEGATIVE |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE |
         CSS_PROPERTY_APPLIES_TO_PLACEHOLDER,
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -952,16 +952,23 @@ nsComputedDOMStyle::SetToRGBAColor(nsROC
   red->SetNumber(NS_GET_R(aColor));
   green->SetNumber(NS_GET_G(aColor));
   blue->SetNumber(NS_GET_B(aColor));
   alpha->SetNumber(nsStyleUtil::ColorComponentToFloat(a));
 
   aValue->SetColor(rgbColor);
 }
 
+void
+nsComputedDOMStyle::SetValueFromComplexColor(nsROCSSPrimitiveValue* aValue,
+                                             const StyleComplexColor& aColor)
+{
+  SetToRGBAColor(aValue, StyleColor()->CalcComplexColor(aColor));
+}
+
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetColor()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   SetToRGBAColor(val, StyleColor()->mColor);
   return val.forget();
 }
 
@@ -3823,20 +3830,17 @@ nsComputedDOMStyle::DoGetTextDecorationS
 
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextEmphasisColor()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-  const nsStyleText* text = StyleText();
-  nscolor color = text->mTextEmphasisColorForeground ?
-    StyleColor()->mColor : text->mTextEmphasisColor;
-  SetToRGBAColor(val, color);
+  SetValueFromComplexColor(val, StyleText()->mTextEmphasisColor);
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextEmphasisPosition()
 {
   auto position = StyleText()->mTextEmphasisPosition;
 
@@ -4071,25 +4075,25 @@ nsComputedDOMStyle::DoGetTextSizeAdjust(
   }
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetWebkitTextFillColor()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-  SetToRGBAColor(val, mStyleContext->GetTextFillColor());
+  SetValueFromComplexColor(val, StyleText()->mWebkitTextFillColor);
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetWebkitTextStrokeColor()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-  SetToRGBAColor(val, mStyleContext->GetTextStrokeColor());
+  SetValueFromComplexColor(val, StyleText()->mWebkitTextStrokeColor);
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetWebkitTextStrokeWidth()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
   val->SetAppUnits(StyleText()->mWebkitTextStrokeWidth.GetCoordValue());
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -6,16 +6,17 @@
 /* DOM object returned from element.getComputedStyle() */
 
 #ifndef nsComputedDOMStyle_h__
 #define nsComputedDOMStyle_h__
 
 #include "mozilla/ArenaRefPtr.h"
 #include "mozilla/ArenaRefPtrInlines.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/StyleComplexColor.h"
 #include "nsCOMPtr.h"
 #include "nscore.h"
 #include "nsCSSProps.h"
 #include "nsDOMCSSDeclaration.h"
 #include "nsStyleContext.h"
 #include "nsIWeakReferenceUtils.h"
 #include "mozilla/gfx/Types.h"
 #include "nsCoord.h"
@@ -578,16 +579,18 @@ private:
 
   /* Custom properties */
   already_AddRefed<CSSValue> DoGetCustomProperty(const nsAString& aPropertyName);
 
   nsDOMCSSValueList* GetROCSSValueList(bool aCommaDelimited);
 
   /* Helper functions */
   void SetToRGBAColor(nsROCSSPrimitiveValue* aValue, nscolor aColor);
+  void SetValueFromComplexColor(nsROCSSPrimitiveValue* aValue,
+                                const mozilla::StyleComplexColor& aColor);
   void SetValueToStyleImage(const nsStyleImage& aStyleImage,
                             nsROCSSPrimitiveValue* aValue);
   void SetValueToPositionCoord(const mozilla::Position::Coord& aCoord,
                                nsROCSSPrimitiveValue* aValue);
   void SetValueToPosition(const mozilla::Position& aPosition,
                           nsDOMCSSValueList* aValueList);
   void SetValueToFragmentOrURL(const mozilla::FragmentOrURL* aFragmentOrURL,
                                nsROCSSPrimitiveValue* aValue);
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -70,16 +70,26 @@
 #include <alloca.h>
 #endif
 
 using std::max;
 using std::min;
 using namespace mozilla;
 using namespace mozilla::dom;
 
+namespace mozilla {
+
+enum UnsetAction
+{
+  eUnsetInitial,
+  eUnsetInherit
+};
+
+} // namespace mozilla
+
 void*
 nsConditionalResetStyleData::GetConditionalStyleData(nsStyleStructID aSID,
                                nsStyleContext* aStyleContext) const
 {
   Entry* e = static_cast<Entry*>(mEntries[aSID]);
   MOZ_ASSERT(e, "if mConditionalBits bit is set, we must have at least one "
                 "conditional style struct");
   do {
@@ -1086,16 +1096,51 @@ static bool SetColor(const nsCSSValue& a
     // contexts (but NOT necessarily new rulenodes).
     aResult = aPresContext->BodyTextColor();
     result = true;
     aConditions.SetUncacheable();
   }
   return result;
 }
 
+template<UnsetAction UnsetTo>
+static void
+SetComplexColor(const nsCSSValue& aValue,
+                const StyleComplexColor& aParentColor,
+                const StyleComplexColor& aInitialColor,
+                nsPresContext* aPresContext,
+                StyleComplexColor& aResult,
+                RuleNodeCacheConditions& aConditions)
+{
+  nsCSSUnit unit = aValue.GetUnit();
+  if (unit == eCSSUnit_Null) {
+    return;
+  }
+  if (unit == eCSSUnit_Initial ||
+      (UnsetTo == eUnsetInitial && unit == eCSSUnit_Unset)) {
+    aResult = aInitialColor;
+  } else if (unit == eCSSUnit_Inherit ||
+             (UnsetTo == eUnsetInherit && unit == eCSSUnit_Unset)) {
+    aConditions.SetUncacheable();
+    aResult = aParentColor;
+  } else if (unit == eCSSUnit_EnumColor &&
+             aValue.GetIntValue() == NS_COLOR_CURRENTCOLOR) {
+    aResult = StyleComplexColor::CurrentColor();
+  } else if (unit == eCSSUnit_ComplexColor) {
+    aResult = aValue.GetStyleComplexColorValue();
+  } else {
+    if (!SetColor(aValue, aParentColor.mColor, aPresContext,
+                  nullptr, aResult.mColor, aConditions)) {
+      MOZ_ASSERT_UNREACHABLE("Unknown color value");
+      return;
+    }
+    aResult.mForegroundRatio = 0;
+  }
+}
+
 static void SetGradientCoord(const nsCSSValue& aValue, nsPresContext* aPresContext,
                              nsStyleContext* aContext, nsStyleCoord& aResult,
                              RuleNodeCacheConditions& aConditions)
 {
   // OK to pass bad aParentCoord since we're not passing SETCOORD_INHERIT
   if (!SetCoord(aValue, aResult, nsStyleCoord(),
                 SETCOORD_LPO | SETCOORD_BOX_POSITION | SETCOORD_STORE_CALC,
                 aContext, aPresContext, aConditions)) {
@@ -4468,16 +4513,23 @@ nsRuleNode::ComputeTextData(void* aStart
                             const nsRuleData* aRuleData,
                             nsStyleContext* aContext,
                             nsRuleNode* aHighestNode,
                             const RuleDetail aRuleDetail,
                             const RuleNodeCacheConditions aConditions)
 {
   COMPUTE_START_INHERITED(Text, text, parentText)
 
+  auto setComplexColor = [&](const nsCSSValue* aValue,
+                             StyleComplexColor nsStyleText::* aField) {
+    SetComplexColor<eUnsetInherit>(*aValue, parentText->*aField,
+                                   StyleComplexColor::CurrentColor(),
+                                   mPresContext, text->*aField, conditions);
+  };
+
   // tab-size: integer, inherit
   SetValue(*aRuleData->ValueForTabSize(),
            text->mTabSize, conditions,
            SETVAL_INTEGER | SETVAL_UNSET_INHERIT, parentText->mTabSize,
            NS_STYLE_TABSIZE_INITIAL);
 
   // letter-spacing: normal, length, inherit
   SetCoord(*aRuleData->ValueForLetterSpacing(),
@@ -4711,36 +4763,18 @@ nsRuleNode::ComputeTextData(void* aStart
   SetValue(*aRuleData->ValueForTextCombineUpright(),
            text->mTextCombineUpright,
            conditions,
            SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
            parentText->mTextCombineUpright,
            NS_STYLE_TEXT_COMBINE_UPRIGHT_NONE);
 
   // text-emphasis-color: color, string, inherit, initial
-  const nsCSSValue*
-    textEmphasisColorValue = aRuleData->ValueForTextEmphasisColor();
-  if (textEmphasisColorValue->GetUnit() == eCSSUnit_Null) {
-    // We don't want to change anything in this case.
-  } else if (textEmphasisColorValue->GetUnit() == eCSSUnit_Inherit ||
-             textEmphasisColorValue->GetUnit() == eCSSUnit_Unset) {
-    conditions.SetUncacheable();
-    text->mTextEmphasisColorForeground =
-      parentText->mTextEmphasisColorForeground;
-    text->mTextEmphasisColor = parentText->mTextEmphasisColor;
-  } else if ((textEmphasisColorValue->GetUnit() == eCSSUnit_EnumColor &&
-              textEmphasisColorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) ||
-             textEmphasisColorValue->GetUnit() == eCSSUnit_Initial) {
-    text->mTextEmphasisColorForeground = true;
-    text->mTextEmphasisColor = mPresContext->DefaultColor();
-  } else {
-    text->mTextEmphasisColorForeground = false;
-    SetColor(*textEmphasisColorValue, 0, mPresContext, aContext,
-             text->mTextEmphasisColor, conditions);
-  }
+  setComplexColor(aRuleData->ValueForTextEmphasisColor(),
+                  &nsStyleText::mTextEmphasisColor);
 
   // text-emphasis-position: enum, inherit, initial
   SetValue(*aRuleData->ValueForTextEmphasisPosition(),
            text->mTextEmphasisPosition,
            conditions,
            SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
            parentText->mTextEmphasisPosition,
            NS_STYLE_TEXT_EMPHASIS_POSITION_OVER |
@@ -4804,57 +4838,22 @@ nsRuleNode::ComputeTextData(void* aStart
   // text-rendering: enum, inherit, initial
   SetValue(*aRuleData->ValueForTextRendering(),
            text->mTextRendering, conditions,
            SETVAL_ENUMERATED | SETVAL_UNSET_INHERIT,
            parentText->mTextRendering,
            NS_STYLE_TEXT_RENDERING_AUTO);
 
   // -webkit-text-fill-color: color, string, inherit, initial
-  const nsCSSValue*
-    webkitTextFillColorValue = aRuleData->ValueForWebkitTextFillColor();
-  if (webkitTextFillColorValue->GetUnit() == eCSSUnit_Null) {
-    // We don't want to change anything in this case.
-  } else if (webkitTextFillColorValue->GetUnit() == eCSSUnit_Inherit ||
-             webkitTextFillColorValue->GetUnit() == eCSSUnit_Unset) {
-    conditions.SetUncacheable();
-    text->mWebkitTextFillColorForeground = parentText->mWebkitTextFillColorForeground;
-    text->mWebkitTextFillColor = parentText->mWebkitTextFillColor;
-  } else if ((webkitTextFillColorValue->GetUnit() == eCSSUnit_EnumColor &&
-              webkitTextFillColorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) ||
-             webkitTextFillColorValue->GetUnit() == eCSSUnit_Initial) {
-    text->mWebkitTextFillColorForeground = true;
-    text->mWebkitTextFillColor = mPresContext->DefaultColor();
-  } else {
-    text->mWebkitTextFillColorForeground = false;
-    SetColor(*webkitTextFillColorValue, 0, mPresContext, aContext,
-             text->mWebkitTextFillColor, conditions);
-  }
+  setComplexColor(aRuleData->ValueForWebkitTextFillColor(),
+                  &nsStyleText::mWebkitTextFillColor);
 
   // -webkit-text-stroke-color: color, string, inherit, initial
-  const nsCSSValue* webkitTextStrokeColorValue =
-    aRuleData->ValueForWebkitTextStrokeColor();
-  if (webkitTextStrokeColorValue->GetUnit() == eCSSUnit_Null) {
-    // We don't want to change anything in this case.
-  } else if (webkitTextStrokeColorValue->GetUnit() == eCSSUnit_Inherit ||
-             webkitTextStrokeColorValue->GetUnit() == eCSSUnit_Unset) {
-    conditions.SetUncacheable();
-    text->mWebkitTextStrokeColorForeground =
-      parentText->mWebkitTextStrokeColorForeground;
-    text->mWebkitTextStrokeColor = parentText->mWebkitTextStrokeColor;
-  } else if ((webkitTextStrokeColorValue->GetUnit() == eCSSUnit_EnumColor &&
-              webkitTextStrokeColorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) ||
-             webkitTextStrokeColorValue->GetUnit() == eCSSUnit_Initial) {
-    text->mWebkitTextStrokeColorForeground = true;
-    text->mWebkitTextStrokeColor = mPresContext->DefaultColor();
-  } else {
-    text->mWebkitTextStrokeColorForeground = false;
-    SetColor(*webkitTextStrokeColorValue, 0, mPresContext, aContext,
-             text->mWebkitTextStrokeColor, conditions);
-  }
+  setComplexColor(aRuleData->ValueForWebkitTextStrokeColor(),
+                  &nsStyleText::mWebkitTextStrokeColor);
 
   // -webkit-text-stroke-width: length, inherit, initial, enum
   const nsCSSValue*
     webkitTextStrokeWidthValue = aRuleData->ValueForWebkitTextStrokeWidth();
   if (webkitTextStrokeWidthValue->GetUnit() == eCSSUnit_Enumerated) {
     NS_ASSERTION(webkitTextStrokeWidthValue->GetIntValue() == NS_STYLE_BORDER_WIDTH_THIN ||
                  webkitTextStrokeWidthValue->GetIntValue() == NS_STYLE_BORDER_WIDTH_MEDIUM ||
                  webkitTextStrokeWidthValue->GetIntValue() == NS_STYLE_BORDER_WIDTH_THICK,
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -1213,24 +1213,18 @@ nsStyleContext::CalcStyleDifferenceInter
         change = true;
       }
     }
 
     // NB: Calling Peek on |this|, not |thisVis| (see above).
     if (!change && PeekStyleText()) {
       const nsStyleText* thisVisText = thisVis->StyleText();
       const nsStyleText* otherVisText = otherVis->StyleText();
-      if (thisVisText->mTextEmphasisColorForeground !=
-          otherVisText->mTextEmphasisColorForeground ||
-          thisVisText->mTextEmphasisColor != otherVisText->mTextEmphasisColor ||
-          thisVisText->mWebkitTextFillColorForeground !=
-          otherVisText->mWebkitTextFillColorForeground ||
+      if (thisVisText->mTextEmphasisColor != otherVisText->mTextEmphasisColor ||
           thisVisText->mWebkitTextFillColor != otherVisText->mWebkitTextFillColor ||
-          thisVisText->mWebkitTextStrokeColorForeground !=
-          otherVisText->mWebkitTextStrokeColorForeground ||
           thisVisText->mWebkitTextStrokeColor != otherVisText->mWebkitTextStrokeColor) {
         change = true;
       }
     }
 
     // NB: Calling Peek on |this|, not |thisVis| (see above).
     if (!change && PeekStyleTextReset()) {
       const nsStyleTextReset *thisVisTextReset = thisVis->StyleTextReset();
@@ -1484,16 +1478,19 @@ ExtractColor(nsCSSPropertyID aProperty,
 {
   StyleAnimationValue val;
   ExtractAnimationValue(aProperty, aStyleContext, val);
   switch (val.GetUnit()) {
     case StyleAnimationValue::eUnit_Color:
       return Some(val.GetCSSValueValue()->GetColorValue());
     case StyleAnimationValue::eUnit_CurrentColor:
       return Some(aStyleContext->StyleColor()->mColor);
+    case StyleAnimationValue::eUnit_ComplexColor:
+      return Some(aStyleContext->StyleColor()->
+                  CalcComplexColor(val.GetStyleComplexColorValue()));
     default:
       return Nothing();
   }
 }
 
 static nscolor
 ExtractColorLenient(nsCSSPropertyID aProperty,
                     nsStyleContext *aStyleContext)
--- a/layout/style/nsStyleContext.h
+++ b/layout/style/nsStyleContext.h
@@ -173,42 +173,16 @@ public:
   //  * !!GetStyleIfVisited() == !!aSourceIfVisited, and, if they're
   //    non-null, GetStyleIfVisited()->mSource == aSourceIfVisited
   //  * RelevantLinkVisited() == aRelevantLinkVisited
   already_AddRefed<nsStyleContext>
   FindChildWithRules(const nsIAtom* aPseudoTag,
                      mozilla::NonOwningStyleContextSource aSource,
                      mozilla::NonOwningStyleContextSource aSourceIfVisited,
                      bool aRelevantLinkVisited);
-  /**
-   * Get the color property that should be used to fill text.
-   */
-  nsCSSPropertyID GetTextFillColorProp() {
-    return StyleText()->mWebkitTextFillColorForeground
-           ? eCSSProperty_color : eCSSProperty__webkit_text_fill_color;
-  }
-
-  /**
-   * Get the color that should be used to fill text: either
-   * the current foreground color, or a separately-specified text fill color.
-   */
-  nscolor GetTextFillColor() {
-    return (GetTextFillColorProp() == eCSSProperty_color)
-           ? StyleColor()->mColor : StyleText()->mWebkitTextFillColor;
-  }
-
-  /**
-   * Get the color that should be used to stroke text: either
-   * the current foreground color, or a separately-specified text stroke color.
-   */
-  nscolor GetTextStrokeColor() {
-    const nsStyleText* textStyle = StyleText();
-    return textStyle->mWebkitTextStrokeColorForeground
-           ? StyleColor()->mColor : textStyle->mWebkitTextStrokeColor;
-  }
 
   // Does this style context or any of its ancestors have text
   // decoration lines?
   // Differs from nsStyleTextReset::HasTextDecorationLines, which tests
   // only the data for a single context.
   bool HasTextDecorationLines() const
     { return !!(mBits & NS_STYLE_HAS_TEXT_DECORATION_LINES); }
 
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -3674,35 +3674,32 @@ AreShadowArraysEqual(nsCSSShadowArray* l
 // nsStyleText
 //
 
 nsStyleText::nsStyleText(StyleStructContext aContext)
   : mTextAlign(NS_STYLE_TEXT_ALIGN_START)
   , mTextAlignLast(NS_STYLE_TEXT_ALIGN_AUTO)
   , mTextAlignTrue(false)
   , mTextAlignLastTrue(false)
-  , mTextEmphasisColorForeground(true)
-  , mWebkitTextFillColorForeground(true)
-  , mWebkitTextStrokeColorForeground(true)
   , mTextTransform(NS_STYLE_TEXT_TRANSFORM_NONE)
   , mWhiteSpace(NS_STYLE_WHITESPACE_NORMAL)
   , mWordBreak(NS_STYLE_WORDBREAK_NORMAL)
   , mOverflowWrap(NS_STYLE_OVERFLOWWRAP_NORMAL)
   , mHyphens(NS_STYLE_HYPHENS_MANUAL)
   , 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(nsCSSParser::ControlCharVisibilityDefault())
   , mTextEmphasisStyle(NS_STYLE_TEXT_EMPHASIS_STYLE_NONE)
   , mTextRendering(NS_STYLE_TEXT_RENDERING_AUTO)
   , mTabSize(NS_STYLE_TABSIZE_INITIAL)
-  , mTextEmphasisColor(aContext.DefaultColor())
-  , mWebkitTextFillColor(aContext.DefaultColor())
-  , mWebkitTextStrokeColor(aContext.DefaultColor())
+  , mTextEmphasisColor(StyleComplexColor::CurrentColor())
+  , mWebkitTextFillColor(StyleComplexColor::CurrentColor())
+  , mWebkitTextStrokeColor(StyleComplexColor::CurrentColor())
   , mWordSpacing(0, nsStyleCoord::CoordConstructor)
   , mLetterSpacing(eStyleUnit_Normal)
   , mLineHeight(eStyleUnit_Normal)
   , mTextIndent(0, nsStyleCoord::CoordConstructor)
   , mWebkitTextStrokeWidth(0, nsStyleCoord::CoordConstructor)
   , mTextShadow(nullptr)
 {
   MOZ_COUNT_CTOR(nsStyleText);
@@ -3713,19 +3710,16 @@ nsStyleText::nsStyleText(StyleStructCont
     NS_STYLE_TEXT_EMPHASIS_POSITION_DEFAULT;
 }
 
 nsStyleText::nsStyleText(const nsStyleText& aSource)
   : mTextAlign(aSource.mTextAlign)
   , mTextAlignLast(aSource.mTextAlignLast)
   , mTextAlignTrue(false)
   , mTextAlignLastTrue(false)
-  , mTextEmphasisColorForeground(aSource.mTextEmphasisColorForeground)
-  , mWebkitTextFillColorForeground(aSource.mWebkitTextFillColorForeground)
-  , mWebkitTextStrokeColorForeground(aSource.mWebkitTextStrokeColorForeground)
   , mTextTransform(aSource.mTextTransform)
   , mWhiteSpace(aSource.mWhiteSpace)
   , mWordBreak(aSource.mWordBreak)
   , mOverflowWrap(aSource.mOverflowWrap)
   , mHyphens(aSource.mHyphens)
   , mRubyAlign(aSource.mRubyAlign)
   , mRubyPosition(aSource.mRubyPosition)
   , mTextSizeAdjust(aSource.mTextSizeAdjust)
@@ -3813,26 +3807,18 @@ nsStyleText::CalcDifference(const nsStyl
     hint |= nsChangeHint_UpdateSubtreeOverflow |
             nsChangeHint_SchedulePaint |
             nsChangeHint_RepaintFrame;
 
     // We don't add any other hints below.
     return hint;
   }
 
-  MOZ_ASSERT(!mTextEmphasisColorForeground ||
-             !aNewData.mTextEmphasisColorForeground ||
-             mTextEmphasisColor == aNewData.mTextEmphasisColor,
-             "If the text-emphasis-color are both foreground color, "
-             "mTextEmphasisColor should also be identical");
-  if (mTextEmphasisColorForeground != aNewData.mTextEmphasisColorForeground ||
-      mTextEmphasisColor != aNewData.mTextEmphasisColor ||
-      mWebkitTextFillColorForeground != aNewData.mWebkitTextFillColorForeground ||
+  if (mTextEmphasisColor != aNewData.mTextEmphasisColor ||
       mWebkitTextFillColor != aNewData.mWebkitTextFillColor ||
-      mWebkitTextStrokeColorForeground != aNewData.mWebkitTextStrokeColorForeground ||
       mWebkitTextStrokeColor != aNewData.mWebkitTextStrokeColor) {
     hint |= nsChangeHint_SchedulePaint |
             nsChangeHint_RepaintFrame;
   }
 
   if (hint) {
     return hint;
   }
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -2085,36 +2085,33 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
            nsChangeHint_ReflowChangesSizeOrPosition |
            nsChangeHint_ClearAncestorIntrinsics;
   }
 
   uint8_t mTextAlign;                   // [inherited] see nsStyleConsts.h
   uint8_t mTextAlignLast;               // [inherited] see nsStyleConsts.h
   bool mTextAlignTrue : 1;              // [inherited] see nsStyleConsts.h
   bool mTextAlignLastTrue : 1;          // [inherited] see nsStyleConsts.h
-  bool mTextEmphasisColorForeground : 1;// [inherited] whether text-emphasis-color is currentColor
-  bool mWebkitTextFillColorForeground : 1;    // [inherited] whether -webkit-text-fill-color is currentColor
-  bool mWebkitTextStrokeColorForeground : 1;  // [inherited] whether -webkit-text-stroke-color is currentColor
   uint8_t mTextTransform;               // [inherited] see nsStyleConsts.h
   uint8_t mWhiteSpace;                  // [inherited] see nsStyleConsts.h
   uint8_t mWordBreak;                   // [inherited] see nsStyleConsts.h
   uint8_t mOverflowWrap;                // [inherited] see nsStyleConsts.h
   uint8_t mHyphens;                     // [inherited] see nsStyleConsts.h
   uint8_t mRubyAlign;                   // [inherited] see nsStyleConsts.h
   uint8_t mRubyPosition;                // [inherited] see nsStyleConsts.h
   uint8_t mTextSizeAdjust;              // [inherited] see nsStyleConsts.h
   uint8_t mTextCombineUpright;          // [inherited] see nsStyleConsts.h
   uint8_t mControlCharacterVisibility;  // [inherited] see nsStyleConsts.h
   uint8_t mTextEmphasisPosition;        // [inherited] see nsStyleConsts.h
   uint8_t mTextEmphasisStyle;           // [inherited] see nsStyleConsts.h
   uint8_t mTextRendering;               // [inherited] see nsStyleConsts.h
   int32_t mTabSize;                     // [inherited] see nsStyleConsts.h
-  nscolor mTextEmphasisColor;           // [inherited]
-  nscolor mWebkitTextFillColor;         // [inherited]
-  nscolor mWebkitTextStrokeColor;       // [inherited]
+  mozilla::StyleComplexColor mTextEmphasisColor;      // [inherited]
+  mozilla::StyleComplexColor mWebkitTextFillColor;    // [inherited]
+  mozilla::StyleComplexColor mWebkitTextStrokeColor;  // [inherited]
 
   nsStyleCoord mWordSpacing;            // [inherited] coord, percent, calc
   nsStyleCoord mLetterSpacing;          // [inherited] coord, normal
   nsStyleCoord mLineHeight;             // [inherited] coord, factor, normal
   nsStyleCoord mTextIndent;             // [inherited] coord, percent, calc
   nsStyleCoord mWebkitTextStrokeWidth;  // [inherited] coord
 
   RefPtr<nsCSSShadowArray> mTextShadow; // [inherited] nullptr in case of a zero-length