Bug 1266621 part 1 - Convert text-decoration-color to store complex color. r=heycam
authorXidorn Quan <me@upsuper.org>
Tue, 27 Sep 2016 20:19:48 +1000
changeset 315752 e99d54b3fabd9ca869df0145f113f566ca5003bf
parent 315751 ac1c4519a19a49e45857d4355bea46b4e1a5fe04
child 315753 e27b031e2249da00131ed79c48bb3c7458736334
push id20634
push usercbook@mozilla.com
push dateFri, 30 Sep 2016 10:10:13 +0000
treeherderfx-team@afe79b010d13 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs1266621
milestone52.0a1
Bug 1266621 part 1 - Convert text-decoration-color to store complex color. r=heycam MozReview-Commit-ID: LEGICgvgQDY
accessible/base/TextAttrs.cpp
layout/generic/nsTextFrame.cpp
layout/reftests/text-decoration/decoration-color-quirks-ref.html
layout/reftests/text-decoration/decoration-color-quirks.html
layout/reftests/text-decoration/decoration-color-standards-ref.html
layout/reftests/text-decoration/decoration-color-standards.html
layout/style/StyleAnimationValue.cpp
layout/style/nsCSSPropList.h
layout/style/nsComputedDOMStyle.cpp
layout/style/nsRuleNode.cpp
layout/style/nsStyleContext.cpp
layout/style/nsStyleStruct.cpp
layout/style/nsStyleStruct.h
layout/style/test/test_transitions_events.html
layout/style/test/test_transitions_per_property.html
layout/xul/nsTextBoxFrame.cpp
--- a/accessible/base/TextAttrs.cpp
+++ b/accessible/base/TextAttrs.cpp
@@ -711,23 +711,19 @@ TextAttrsMgr::AutoGeneratedTextAttr::
 ////////////////////////////////////////////////////////////////////////////////
 // TextDecorTextAttr
 ////////////////////////////////////////////////////////////////////////////////
 
 TextAttrsMgr::TextDecorValue::
   TextDecorValue(nsIFrame* aFrame)
 {
   const nsStyleTextReset* textReset = aFrame->StyleTextReset();
-  mStyle = textReset->GetDecorationStyle();
-
-  bool isForegroundColor = false;
-  textReset->GetDecorationColor(mColor, isForegroundColor);
-  if (isForegroundColor)
-    mColor = aFrame->StyleColor()->mColor;
-
+  mStyle = textReset->mTextDecorationStyle;
+  mColor = aFrame->StyleColor()->
+    CalcComplexColor(textReset->mTextDecorationColor);
   mLine = textReset->mTextDecorationLine &
     (NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE |
      NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH);
 }
 
 TextAttrsMgr::TextDecorTextAttr::
   TextDecorTextAttr(nsIFrame* aRootFrame, nsIFrame* aFrame) :
   TTextAttr<TextDecorValue>(!aFrame)
--- a/layout/generic/nsTextFrame.cpp
+++ b/layout/generic/nsTextFrame.cpp
@@ -5170,17 +5170,17 @@ nsTextFrame::GetTextDecorations(
         f->GetLogicalBaseline(wm);
       baselineOffset = physicalBlockStartOffset - offset;
     }
 
     nearestBlockFound = nearestBlockFound || firstBlock;
     physicalBlockStartOffset +=
       vertical ? f->GetNormalPosition().x : f->GetNormalPosition().y;
 
-    const uint8_t style = styleText->GetDecorationStyle();
+    const uint8_t style = styleText->mTextDecorationStyle;
     if (textDecorations) {
       nscolor color;
       if (useOverride) {
         color = overrideColor;
       } else if (IsSVGText()) {
         // XXX We might want to do something with text-decoration-color when
         //     painting SVG text, but it's not clear what we should do.  We
         //     at least need SVG text decorations to paint with 'fill' if
@@ -5379,17 +5379,17 @@ nsTextFrame::UnionAdditionalOverflow(nsP
   const gfxFloat appUnitsPerDevUnit = aPresContext->AppUnitsPerDevPixel();
 
   if (IsFloatingFirstLetterChild()) {
     bool inverted = wm.IsLineInverted();
     // The underline/overline drawable area must be contained in the overflow
     // rect when this is in floating first letter frame at *both* modes.
     // In this case, aBlock is the ::first-letter frame.
     uint8_t decorationStyle = aBlock->StyleContext()->
-                                StyleTextReset()->GetDecorationStyle();
+                                StyleTextReset()->mTextDecorationStyle;
     // If the style is none, let's include decoration line rect as solid style
     // since changing the style from none to solid/dotted/dashed doesn't cause
     // reflow.
     if (decorationStyle == NS_STYLE_TEXT_DECORATION_STYLE_NONE) {
       decorationStyle = NS_STYLE_TEXT_DECORATION_STYLE_SOLID;
     }
     nsFontMetrics* fontMetrics = aProvider.GetFontMetrics();
     nscoord underlineOffset, underlineSize;
--- a/layout/reftests/text-decoration/decoration-color-quirks-ref.html
+++ b/layout/reftests/text-decoration/decoration-color-quirks-ref.html
@@ -45,18 +45,18 @@
     here is specified red decoration color but has current color lines</span>,
   and here are current color decoration lines.
 </p>
 <p style="color: blue;">
   This is blue paragraph,
   <span style="font-size:2em;
                color: red;
                text-decoration: underline line-through overline;
-               text-decoration-color: blue;">
-    here is red text with blue decoration lines</span>,
+               text-decoration-color: red;">
+    here is red text with red decoration lines</span>,
   and here is blue text without decoration lines.
 </p>
 <p style="color: blue;">
   This is blue paragraph and decoration color is specified as green,
   <span style="font-size:2em;
                color: red;
                text-decoration: underline line-through overline;
                text-decoration-color: green;">
--- a/layout/reftests/text-decoration/decoration-color-quirks.html
+++ b/layout/reftests/text-decoration/decoration-color-quirks.html
@@ -53,17 +53,17 @@
   and here are current color decoration lines.
 </p>
 <p style="color: blue;">
   This is blue paragraph,
   <span style="font-size:2em;
                color: red;
                text-decoration: underline line-through overline;
                text-decoration-color: inherit;">
-    here is red text with blue decoration lines</span>,
+    here is red text with red decoration lines</span>,
   and here is blue text without decoration lines.
 </p>
 <p style="color: blue;
           text-decoration-color: green;">
   This is blue paragraph and decoration color is specified as green,
   <span style="font-size:2em;
                color: red;
                text-decoration: underline line-through overline;
--- a/layout/reftests/text-decoration/decoration-color-standards-ref.html
+++ b/layout/reftests/text-decoration/decoration-color-standards-ref.html
@@ -47,18 +47,18 @@
     here is specified red decoration color but has current color lines</span>,
   and here are current color decoration lines.
 </p>
 <p style="color: blue;">
   This is blue paragraph,
   <span style="font-size:2em;
                color: red;
                text-decoration: underline line-through overline;
-               text-decoration-color: blue;">
-    here is red text with blue decoration lines</span>,
+               text-decoration-color: red;">
+    here is red text with red decoration lines</span>,
   and here is blue text without decoration lines.
 </p>
 <p style="color: blue;">
   This is blue paragraph and decoration color is specified as green,
   <span style="font-size:2em;
                color: red;
                text-decoration: underline line-through overline;
                text-decoration-color: green;">
--- a/layout/reftests/text-decoration/decoration-color-standards.html
+++ b/layout/reftests/text-decoration/decoration-color-standards.html
@@ -52,17 +52,17 @@
   and here are current color decoration lines.
 </p>
 <p style="color: blue;">
   This is blue paragraph,
   <span style="font-size:2em;
                color: red;
                text-decoration: underline line-through overline;
                text-decoration-color: inherit;">
-    here is red text with blue decoration lines</span>,
+    here is red text with red decoration lines</span>,
   and here is blue text without decoration lines.
 </p>
 <p style="color: blue;
           text-decoration-color: green;">
   This is blue paragraph and decoration color is specified as green,
   <span style="font-size:2em;
                color: red;
                text-decoration: underline line-through overline;
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -3890,37 +3890,16 @@ StyleAnimationValue::ExtractComputedValu
         case eCSSProperty_order: {
           const nsStylePosition *stylePosition =
             static_cast<const nsStylePosition*>(styleStruct);
           aComputedValue.SetIntValue(stylePosition->mOrder,
                                      eUnit_Integer);
           break;
         }
 
-        case eCSSProperty_text_decoration_color: {
-          const nsStyleTextReset *styleTextReset =
-            static_cast<const nsStyleTextReset*>(styleStruct);
-          nscolor color;
-          bool isForeground;
-          styleTextReset->GetDecorationColor(color, isForeground);
-          if (isForeground) {
-            color = aStyleContext->StyleColor()->mColor;
-          }
-          aComputedValue.SetColorValue(color);
-          break;
-        }
-
-        case eCSSProperty_text_decoration_style: {
-          uint8_t decorationStyle =
-            static_cast<const nsStyleTextReset*>(styleStruct)->
-              GetDecorationStyle();
-          aComputedValue.SetIntValue(decorationStyle, eUnit_Enumerated);
-          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
@@ -3935,18 +3935,18 @@ CSS_PROP_TEXTRESET(
     TextDecorationColor,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE |
         CSS_PROPERTY_APPLIES_TO_PLACEHOLDER |
         CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED,
     "",
     VARIANT_HCK,
     kBorderColorKTable,
-    CSS_PROP_NO_OFFSET,
-    eStyleAnimType_Custom)
+    offsetof(nsStyleTextReset, mTextDecorationColor),
+    eStyleAnimType_ComplexColor)
 CSS_PROP_TEXTRESET(
     text-decoration-line,
     text_decoration_line,
     TextDecorationLine,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_VALUE_PARSER_FUNCTION |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE |
         CSS_PROPERTY_APPLIES_TO_PLACEHOLDER,
@@ -3961,17 +3961,17 @@ CSS_PROP_TEXTRESET(
     TextDecorationStyle,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE |
         CSS_PROPERTY_APPLIES_TO_PLACEHOLDER,
     "",
     VARIANT_HK,
     kTextDecorationStyleKTable,
     CSS_PROP_NO_OFFSET,
-    eStyleAnimType_Custom)
+    eStyleAnimType_None)
 CSS_PROP_SHORTHAND(
     text-emphasis,
     text_emphasis,
     TextEmphasis,
     CSS_PROPERTY_PARSE_FUNCTION,
     "")
 CSS_PROP_TEXT(
     text-emphasis-color,
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -3751,52 +3751,41 @@ nsComputedDOMStyle::DoGetTextCombineUpri
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextDecoration()
 {
   const nsStyleTextReset* textReset = StyleTextReset();
 
   bool isInitialStyle =
-    textReset->GetDecorationStyle() == NS_STYLE_TEXT_DECORATION_STYLE_SOLID;
-  nscolor color;
-  bool isForegroundColor;
-  textReset->GetDecorationColor(color, isForegroundColor);
-
-  if (isInitialStyle && isForegroundColor) {
+    textReset->mTextDecorationStyle == NS_STYLE_TEXT_DECORATION_STYLE_SOLID;
+  StyleComplexColor color = textReset->mTextDecorationColor;
+
+  if (isInitialStyle && color.IsCurrentColor()) {
     return DoGetTextDecorationLine();
   }
 
   RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
 
   valueList->AppendCSSValue(DoGetTextDecorationLine());
   if (!isInitialStyle) {
     valueList->AppendCSSValue(DoGetTextDecorationStyle());
   }
-  if (!isForegroundColor) {
+  if (!color.IsCurrentColor()) {
     valueList->AppendCSSValue(DoGetTextDecorationColor());
   }
 
   return valueList.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextDecorationColor()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
-
-  nscolor color;
-  bool isForeground;
-  StyleTextReset()->GetDecorationColor(color, isForeground);
-  if (isForeground) {
-    color = StyleColor()->mColor;
-  }
-
-  SetToRGBAColor(val, color);
-
+  SetValueFromComplexColor(val, StyleTextReset()->mTextDecorationColor);
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextDecorationLine()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
@@ -3820,17 +3809,17 @@ nsComputedDOMStyle::DoGetTextDecorationL
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextDecorationStyle()
 {
   RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
 
   val->SetIdent(
-    nsCSSProps::ValueToKeywordEnum(StyleTextReset()->GetDecorationStyle(),
+    nsCSSProps::ValueToKeywordEnum(StyleTextReset()->mTextDecorationStyle,
                                    nsCSSProps::kTextDecorationStyleKTable));
 
   return val.forget();
 }
 
 already_AddRefed<CSSValue>
 nsComputedDOMStyle::DoGetTextEmphasisColor()
 {
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -1123,18 +1123,20 @@ SetComplexColor(const nsCSSValue& aValue
   }
   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) {
+  } else if ((unit == eCSSUnit_EnumColor &&
+              aValue.GetIntValue() == NS_COLOR_CURRENTCOLOR) ||
+             (unit == eCSSUnit_Enumerated &&
+              aValue.GetIntValue() == NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR)) {
     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;
@@ -4917,62 +4919,33 @@ nsRuleNode::ComputeTextResetData(void* a
     conditions.SetUncacheable();
     text->mTextDecorationLine = parentText->mTextDecorationLine;
   } else if (eCSSUnit_Initial == decorationLineValue->GetUnit() ||
              eCSSUnit_Unset == decorationLineValue->GetUnit()) {
     text->mTextDecorationLine = NS_STYLE_TEXT_DECORATION_LINE_NONE;
   }
 
   // text-decoration-color: color, string, enum, inherit, initial
-  const nsCSSValue* decorationColorValue =
-    aRuleData->ValueForTextDecorationColor();
-  nscolor decorationColor;
-  if (eCSSUnit_Inherit == decorationColorValue->GetUnit()) {
-    conditions.SetUncacheable();
-    if (parentContext) {
-      bool isForeground;
-      parentText->GetDecorationColor(decorationColor, isForeground);
-      if (isForeground) {
-        text->SetDecorationColor(parentContext->StyleColor()->mColor);
-      } else {
-        text->SetDecorationColor(decorationColor);
-      }
-    } else {
-      text->SetDecorationColorToForeground();
-    }
-  }
-  else if (eCSSUnit_EnumColor == decorationColorValue->GetUnit() &&
-           decorationColorValue->GetIntValue() == NS_COLOR_CURRENTCOLOR) {
-    text->SetDecorationColorToForeground();
-  }
-  else if (SetColor(*decorationColorValue, 0, mPresContext, aContext,
-                    decorationColor, conditions)) {
-    text->SetDecorationColor(decorationColor);
-  }
-  else if (eCSSUnit_Initial == decorationColorValue->GetUnit() ||
-           eCSSUnit_Unset == decorationColorValue->GetUnit() ||
-           eCSSUnit_Enumerated == decorationColorValue->GetUnit()) {
-    MOZ_ASSERT(eCSSUnit_Enumerated != decorationColorValue->GetUnit() ||
-               decorationColorValue->GetIntValue() ==
-                 NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR,
-               "unexpected enumerated value");
-    text->SetDecorationColorToForeground();
-  }
+  SetComplexColor<eUnsetInitial>(*aRuleData->ValueForTextDecorationColor(),
+                                 parentText->mTextDecorationColor,
+                                 StyleComplexColor::CurrentColor(),
+                                 mPresContext,
+                                 text->mTextDecorationColor, conditions);
 
   // text-decoration-style: enum, inherit, initial
   const nsCSSValue* decorationStyleValue =
     aRuleData->ValueForTextDecorationStyle();
   if (eCSSUnit_Enumerated == decorationStyleValue->GetUnit()) {
-    text->SetDecorationStyle(decorationStyleValue->GetIntValue());
+    text->mTextDecorationStyle = decorationStyleValue->GetIntValue();
   } else if (eCSSUnit_Inherit == decorationStyleValue->GetUnit()) {
-    text->SetDecorationStyle(parentText->GetDecorationStyle());
+    text->mTextDecorationStyle = parentText->mTextDecorationStyle;
     conditions.SetUncacheable();
   } else if (eCSSUnit_Initial == decorationStyleValue->GetUnit() ||
              eCSSUnit_Unset == decorationStyleValue->GetUnit()) {
-    text->SetDecorationStyle(NS_STYLE_TEXT_DECORATION_STYLE_SOLID);
+    text->mTextDecorationStyle = NS_STYLE_TEXT_DECORATION_STYLE_SOLID;
   }
 
   // text-overflow: enum, string, pair(enum|string), inherit, initial
   const nsCSSValue* textOverflowValue =
     aRuleData->ValueForTextOverflow();
   if (eCSSUnit_Initial == textOverflowValue->GetUnit() ||
       eCSSUnit_Unset == textOverflowValue->GetUnit()) {
     text->mTextOverflow = nsStyleTextOverflow();
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -1228,27 +1228,18 @@ nsStyleContext::CalcStyleDifferenceInter
         change = true;
       }
     }
 
     // NB: Calling Peek on |this|, not |thisVis| (see above).
     if (!change && PeekStyleTextReset()) {
       const nsStyleTextReset *thisVisTextReset = thisVis->StyleTextReset();
       const nsStyleTextReset *otherVisTextReset = otherVis->StyleTextReset();
-      // Dummy initialisations to keep Valgrind/Memcheck happy.
-      // See bug 1122375 comment 4.
-      nscolor thisVisDecColor = NS_RGBA(0, 0, 0, 0);
-      nscolor otherVisDecColor = NS_RGBA(0, 0, 0, 0);
-      bool thisVisDecColorIsFG, otherVisDecColorIsFG;
-      thisVisTextReset->GetDecorationColor(thisVisDecColor,
-                                           thisVisDecColorIsFG);
-      otherVisTextReset->GetDecorationColor(otherVisDecColor,
-                                            otherVisDecColorIsFG);
-      if (thisVisDecColorIsFG != otherVisDecColorIsFG ||
-          (!thisVisDecColorIsFG && thisVisDecColor != otherVisDecColor)) {
+      if (thisVisTextReset->mTextDecorationColor !=
+          otherVisTextReset->mTextDecorationColor) {
         change = true;
       }
     }
 
     // NB: Calling Peek on |this|, not |thisVis| (see above).
     if (!change && PeekStyleSVG()) {
       const nsStyleSVG *thisVisSVG = thisVis->StyleSVG();
       const nsStyleSVG *otherVisSVG = otherVis->StyleSVG();
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -3594,21 +3594,21 @@ nsStyleContent::CalcDifference(const nsS
 }
 
 // --------------------
 // nsStyleTextReset
 //
 
 nsStyleTextReset::nsStyleTextReset(StyleStructContext aContext)
   : mTextDecorationLine(NS_STYLE_TEXT_DECORATION_LINE_NONE)
+  , mTextDecorationStyle(NS_STYLE_TEXT_DECORATION_STYLE_SOLID)
   , mUnicodeBidi(NS_STYLE_UNICODE_BIDI_NORMAL)
   , mInitialLetterSink(0)
   , mInitialLetterSize(0.0f)
-  , mTextDecorationStyle(NS_STYLE_TEXT_DECORATION_STYLE_SOLID | BORDER_COLOR_FOREGROUND)
-  , mTextDecorationColor(NS_RGB(0, 0, 0))
+  , mTextDecorationColor(StyleComplexColor::CurrentColor())
 {
   MOZ_COUNT_CTOR(nsStyleTextReset);
 }
 
 nsStyleTextReset::nsStyleTextReset(const nsStyleTextReset& aSource)
 {
   MOZ_COUNT_CTOR(nsStyleTextReset);
   *this = aSource;
@@ -3623,37 +3623,28 @@ nsChangeHint
 nsStyleTextReset::CalcDifference(const nsStyleTextReset& aNewData) const
 {
   if (mUnicodeBidi != aNewData.mUnicodeBidi ||
       mInitialLetterSink != aNewData.mInitialLetterSink ||
       mInitialLetterSize != aNewData.mInitialLetterSize) {
     return NS_STYLE_HINT_REFLOW;
   }
 
-  uint8_t lineStyle = GetDecorationStyle();
-  uint8_t otherLineStyle = aNewData.GetDecorationStyle();
   if (mTextDecorationLine != aNewData.mTextDecorationLine ||
-      lineStyle != otherLineStyle) {
+      mTextDecorationStyle != aNewData.mTextDecorationStyle) {
     // Changes to our text-decoration line can impact our overflow area &
     // also our descendants' overflow areas (particularly for text-frame
     // descendants).  So, we update those areas & trigger a repaint.
     return nsChangeHint_RepaintFrame |
            nsChangeHint_UpdateSubtreeOverflow |
            nsChangeHint_SchedulePaint;
   }
 
   // Repaint for decoration color changes
-  // Dummy initialisations to keep Valgrind/Memcheck happy.
-  // See bug 1289098 comment 1.
-  nscolor decColor = NS_RGBA(0, 0, 0, 0);
-  nscolor otherDecColor = NS_RGBA(0, 0, 0, 0);
-  bool isFG, otherIsFG;
-  GetDecorationColor(decColor, isFG);
-  aNewData.GetDecorationColor(otherDecColor, otherIsFG);
-  if (isFG != otherIsFG || (!isFG && decColor != otherDecColor)) {
+  if (mTextDecorationColor != aNewData.mTextDecorationColor) {
     return nsChangeHint_RepaintFrame;
   }
 
   if (mTextOverflow != aNewData.mTextOverflow) {
     return nsChangeHint_RepaintFrame;
   }
 
   return nsChangeHint(0);
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1992,53 +1992,16 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
 
   // Note the difference between this and
   // nsStyleContext::HasTextDecorationLines.
   bool HasTextDecorationLines() const {
     return mTextDecorationLine != NS_STYLE_TEXT_DECORATION_LINE_NONE &&
            mTextDecorationLine != NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL;
   }
 
-  uint8_t GetDecorationStyle() const
-  {
-    return (mTextDecorationStyle & BORDER_STYLE_MASK);
-  }
-
-  void SetDecorationStyle(uint8_t aStyle)
-  {
-    MOZ_ASSERT((aStyle & BORDER_STYLE_MASK) == aStyle,
-               "style doesn't fit");
-    mTextDecorationStyle &= ~BORDER_STYLE_MASK;
-    mTextDecorationStyle |= (aStyle & BORDER_STYLE_MASK);
-  }
-
-  void GetDecorationColor(nscolor& aColor, bool& aForeground) const
-  {
-    aForeground = false;
-    if ((mTextDecorationStyle & BORDER_COLOR_SPECIAL) == 0) {
-      aColor = mTextDecorationColor;
-    } else if (mTextDecorationStyle & BORDER_COLOR_FOREGROUND) {
-      aForeground = true;
-    } else {
-      NS_NOTREACHED("OUTLINE_COLOR_INITIAL should not be set here");
-    }
-  }
-
-  void SetDecorationColor(nscolor aColor)
-  {
-    mTextDecorationColor = aColor;
-    mTextDecorationStyle &= ~BORDER_COLOR_SPECIAL;
-  }
-
-  void SetDecorationColorToForeground()
-  {
-    mTextDecorationStyle &= ~BORDER_COLOR_SPECIAL;
-    mTextDecorationStyle |= BORDER_COLOR_FOREGROUND;
-  }
-
   nsChangeHint CalcDifference(const nsStyleTextReset& aNewData) const;
   static nsChangeHint MaxDifference() {
     return nsChangeHint(
         NS_STYLE_HINT_REFLOW |
         nsChangeHint_UpdateSubtreeOverflow);
   }
   static nsChangeHint DifferenceAlwaysHandledForDescendants() {
     // CalcDifference never returns the reflow hints that are sometimes
@@ -2046,23 +2009,21 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt
     return nsChangeHint_NeedReflow |
            nsChangeHint_ReflowChangesSizeOrPosition |
            nsChangeHint_ClearAncestorIntrinsics;
   }
 
   nsStyleTextOverflow mTextOverflow;    // [reset] enum, string
 
   uint8_t mTextDecorationLine;          // [reset] see nsStyleConsts.h
+  uint8_t mTextDecorationStyle;         // [reset] see nsStyleConsts.h
   uint8_t mUnicodeBidi;                 // [reset] see nsStyleConsts.h
   nscoord mInitialLetterSink;           // [reset] 0 means normal
   float mInitialLetterSize;             // [reset] 0.0f means normal
-protected:
-  uint8_t mTextDecorationStyle;         // [reset] see nsStyleConsts.h
-
-  nscolor mTextDecorationColor;         // [reset] the colors to use for a decoration lines, not used at currentColor
+  mozilla::StyleComplexColor mTextDecorationColor; // [reset]
 };
 
 struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleText
 {
   explicit nsStyleText(StyleStructContext aContext);
   nsStyleText(const nsStyleText& aOther);
   ~nsStyleText();
 
--- a/layout/style/test/test_transitions_events.html
+++ b/layout/style/test/test_transitions_events.html
@@ -67,17 +67,16 @@ function cs(id) { return getComputedStyl
 
 var got_one_root = false;
 var got_one_target = false;
 var got_one_target_bordertop = false;
 var got_one_target_borderright = false;
 var got_one_target_borderbottom = false;
 var got_one_target_borderleft = false;
 var got_one_target_columnrule = false;
-var got_one_target_textdecorationcolor = false;
 var got_one_target_outlinecolor = false;
 var got_two_target = false;
 var got_three_top = false;
 var got_three_right = false;
 var got_three_bottom = false;
 var got_three_left = false;
 var got_four_root = false;
 var got_body = false;
@@ -179,22 +178,16 @@ document.documentElement.addEventListene
         event.stopPropagation();
         break;
       case "-moz-column-rule-color":
         ok(!got_one_target_columnrule,
            "transitionend on one on target (-moz-column-rule-color)");
         got_one_target_columnrule = true;
         event.stopPropagation();
         break;
-      case "text-decoration-color":
-        ok(!got_one_target_textdecorationcolor,
-           "transitionend on one on target (text-decoration-color)");
-        got_one_target_textdecorationcolor = true;
-        event.stopPropagation();
-        break;
       case "outline-color":
         ok(!got_one_target_outlinecolor,
            "transitionend on one on target (outline-color)");
         got_one_target_outlinecolor = true;
         event.stopPropagation();
         break;
       default:
         ok(false, "unexpected property name " + event.propertyName +
@@ -209,17 +202,16 @@ document.documentElement.addEventListene
 
 started_test(); // color on #one
 started_test(); // border-top-color on #one
 started_test(); // border-right-color on #one
 started_test(); // border-right-color on #one (listener on root)
 started_test(); // border-bottom-color on #one
 started_test(); // border-left-color on #one
 started_test(); // -moz-column-rule-color on #one
-started_test(); // text-decoration-color on #one
 started_test(); // outline-color on #one
 $("one").style.color = "lime";
 
 
 $("two").addEventListener("transitionend",
   function(event) {
     event.stopPropagation();
 
--- a/layout/style/test/test_transitions_per_property.html
+++ b/layout/style/test/test_transitions_per_property.html
@@ -258,18 +258,17 @@ var supported_properties = {
     // NOTE: when calc() is supported on 'stroke-width', we should add
     // test_length_percent_calc_transition.
     "stroke-width": [ test_length_transition_svg, test_percent_transition,
                       test_length_clamped_svg, test_percent_clamped ],
     "text-decoration": [ test_color_shorthand_transition,
                          test_currentcolor_shorthand_transition,
                          test_border_color_shorthand_transition ],
     "text-decoration-color": [ test_color_transition,
-                               test_currentcolor_transition,
-                               test_border_color_transition ],
+                               test_true_currentcolor_transition ],
     "text-emphasis-color": [ test_color_transition,
                              test_true_currentcolor_transition ],
     "text-indent": [ test_length_transition, test_percent_transition,
                      test_length_percent_calc_transition,
                      test_length_unclamped, test_percent_unclamped ],
     "text-shadow": [ test_shadow_transition ],
     "top": [ test_length_transition, test_percent_transition,
              test_length_percent_calc_transition,
--- a/layout/xul/nsTextBoxFrame.cpp
+++ b/layout/xul/nsTextBoxFrame.cpp
@@ -422,23 +422,20 @@ nsTextBoxFrame::DrawText(nsRenderingCont
       }
       const nsStyleTextReset* styleText = context->StyleTextReset();
 
       if (decorMask & styleText->mTextDecorationLine) {  // a decoration defined here
         nscolor color;
         if (aOverrideColor) {
           color = *aOverrideColor;
         } else {
-          bool isForeground;
-          styleText->GetDecorationColor(color, isForeground);
-          if (isForeground) {
-            color = nsLayoutUtils::GetColor(f, eCSSProperty_color);
-          }
+          color = context->StyleColor()->
+            CalcComplexColor(styleText->mTextDecorationColor);
         }
-        uint8_t style = styleText->GetDecorationStyle();
+        uint8_t style = styleText->mTextDecorationStyle;
 
         if (NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE & decorMask &
               styleText->mTextDecorationLine) {
           underColor = color;
           underStyle = style;
           decorMask &= ~NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
           decorations |= NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
         }