Bug 1260543 - Treat currentcolor as computed value which is not interpolatable with actual color for text-emphasis-color and -webkit-text-fill-color. r=birtles draft
authorXidorn Quan <quanxunzhen@gmail.com>
Fri, 08 Apr 2016 13:43:09 +1000
changeset 355181 83f47535dc6f5a1f5fe72f60ba4877ec9a16a6df
parent 355180 8472fb7f648b9c5af8b0dbb6016f23c461b6ab45
child 519133 3fdba50f1dfbc1891ccce5b0d41226d67aa16c52
push id16220
push userxquan@mozilla.com
push dateFri, 22 Apr 2016 01:44:04 +0000
reviewersbirtles
bugs1260543
milestone48.0a1
Bug 1260543 - Treat currentcolor as computed value which is not interpolatable with actual color for text-emphasis-color and -webkit-text-fill-color. r=birtles MozReview-Commit-ID: GUXEDHxOdNC
layout/reftests/bugs/1260543-1-ref.html
layout/reftests/bugs/1260543-1.html
layout/reftests/bugs/reftest.list
layout/style/StyleAnimationValue.cpp
layout/style/StyleAnimationValue.h
layout/style/nsStyleContext.cpp
layout/style/test/test_transitions_events.html
layout/style/test/test_transitions_per_property.html
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1260543-1-ref.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+<style>
+#outer {
+  font-size: 52px;
+  color: green;
+}
+</style>
+<p>Test passes if the block below is green.</p>
+<div id="outer"><span id="inner">&#x2588;</span></div>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/1260543-1.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<html class="reftest-wait">
+<style>
+#outer {
+  font-size: 52px;
+  transition: all 100s step-start;
+  color: transparent;
+}
+#outer.red {
+  color: red;
+}
+#outer.red > #inner {
+  color: green;
+}
+</style>
+<!--
+This is testing that -webkit-text-fill-color should inherit currentcolor
+keyword value, rather than the computed value of color (used value of
+-webkit-text-fill-color) from the transition.
+-->
+<p>Test passes if the block below is green.</p>
+<div id="outer"><span id="inner">&#x2588;</span></div>
+<script>
+window.addEventListener("load", () => {
+  // Wait for the second frame to ensure that we will
+  // actually start the transition.
+  requestAnimationFrame(() => {
+    requestAnimationFrame(() => {
+      let outer = document.getElementById("outer");
+      outer.className = "red";
+      document.documentElement.className = "";
+    });
+  });
+});
+</script>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1944,8 +1944,9 @@ fuzzy(1,74) fuzzy-if(gtkWidget,6,79) == 
 == 1222226-1.html 1222226-1-ref.html
 pref(layout.css.overflow-clip-box.enabled,true) == 1226278.html 1226278-ref.html
 == 1230466.html about:blank
 random-if(gtkWidget) != 1238243-1.html 1238243-1-notref.html # may fail on Linux, depending on Korean fonts available
 random-if(OSX==1006) == 1238243-2.html 1238243-2-ref.html # fails on 10.6 with default fonts because filler has a visible glyph
 fuzzy(100,2000) == 1239564.html 1239564-ref.html
 == 1242172-1.html 1242172-1-ref.html
 == 1242172-2.html 1242172-2-ref.html
+== 1260543-1.html 1260543-1-ref.html
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -463,16 +463,17 @@ StyleAnimationValue::ComputeDistance(nsC
 
   switch (commonUnit) {
     case eUnit_Null:
     case eUnit_Auto:
     case eUnit_None:
     case eUnit_Normal:
     case eUnit_UnparsedString:
     case eUnit_URL:
+    case eUnit_CurrentColor:
       return false;
 
     case eUnit_Enumerated:
       switch (aProperty) {
         case eCSSProperty_font_stretch: {
           // just like eUnit_Integer.
           int32_t startInt = aStartValue.GetIntValue();
           int32_t endInt = aEndValue.GetIntValue();
@@ -2207,16 +2208,17 @@ StyleAnimationValue::AddWeighted(nsCSSPr
 
   switch (commonUnit) {
     case eUnit_Null:
     case eUnit_Auto:
     case eUnit_None:
     case eUnit_Normal:
     case eUnit_UnparsedString:
     case eUnit_URL:
+    case eUnit_CurrentColor:
       return false;
 
     case eUnit_Enumerated:
       switch (aProperty) {
         case eCSSProperty_font_stretch: {
           // Animate just like eUnit_Integer.
           int32_t result = floor(aCoeff1 * double(aValue1.GetIntValue()) +
                                  aCoeff2 * double(aValue2.GetIntValue()));
@@ -3002,16 +3004,19 @@ StyleAnimationValue::UncomputeValue(nsCS
     case eUnit_Float:
       aSpecifiedValue.
         SetFloatValue(aComputedValue.GetFloatValue(), eCSSUnit_Number);
       break;
     case eUnit_Color:
       // colors can be alone, or part of a paint server
       aSpecifiedValue.SetColorValue(aComputedValue.GetColorValue());
       break;
+    case eUnit_CurrentColor:
+      aSpecifiedValue.SetIntValue(NS_COLOR_CURRENTCOLOR, eCSSUnit_EnumColor);
+      break;
     case eUnit_Calc:
     case eUnit_ObjectPosition:
     case eUnit_URL: {
       nsCSSValue* val = aComputedValue.GetCSSValueValue();
       // Sanity-check that the underlying unit in the nsCSSValue is what we
       // expect for our StyleAnimationValue::Unit:
       MOZ_ASSERT((unit == eUnit_Calc && val->GetUnit() == eCSSUnit_Calc) ||
                  (unit == eUnit_ObjectPosition &&
@@ -3144,16 +3149,27 @@ StyleDataAtOffset(const void* aStyleStru
 
 inline void*
 StyleDataAtOffset(void* aStyleStruct, ptrdiff_t aOffset)
 {
   return reinterpret_cast<char*>(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);
@@ -3600,24 +3616,27 @@ StyleAnimationValue::ExtractComputedValu
             static_cast<const nsStyleTextReset*>(styleStruct)->
               GetDecorationStyle();
           aComputedValue.SetIntValue(decorationStyle, eUnit_Enumerated);
           break;
         }
 
         case eCSSProperty_text_emphasis_color: {
           auto styleText = static_cast<const nsStyleText*>(styleStruct);
-          nscolor color = styleText->mTextEmphasisColorForeground ?
-            aStyleContext->StyleColor()->mColor : styleText->mTextEmphasisColor;
-          aComputedValue.SetColorValue(color);
+          SetCurrentOrActualColor(styleText->mTextEmphasisColorForeground,
+                                  styleText->mTextEmphasisColor,
+                                  aComputedValue);
           break;
         }
 
         case eCSSProperty__webkit_text_fill_color: {
-          aComputedValue.SetColorValue(aStyleContext->GetTextFillColor());
+          auto styleText = static_cast<const nsStyleText*>(styleStruct);
+          SetCurrentOrActualColor(styleText->mWebkitTextFillColorForeground,
+                                  styleText->mWebkitTextFillColor,
+                                  aComputedValue);
           break;
         }
 
         case eCSSProperty_border_spacing: {
           const nsStyleTableBorder *styleTableBorder =
             static_cast<const nsStyleTableBorder*>(styleStruct);
           nsAutoPtr<nsCSSValuePair> pair(new nsCSSValuePair);
           nscoordToCSSValue(styleTableBorder->mBorderSpacingCol, pair->mXValue);
@@ -4173,16 +4192,17 @@ StyleAnimationValue::operator=(const Sty
   FreeValue();
 
   mUnit = aOther.mUnit;
   switch (mUnit) {
     case eUnit_Null:
     case eUnit_Normal:
     case eUnit_Auto:
     case eUnit_None:
+    case eUnit_CurrentColor:
       break;
     case eUnit_Enumerated:
     case eUnit_Visibility:
     case eUnit_Integer:
       mValue.mInt = aOther.mValue.mInt;
       break;
     case eUnit_Coord:
       mValue.mCoord = aOther.mValue.mCoord;
@@ -4315,16 +4335,23 @@ void
 StyleAnimationValue::SetColorValue(nscolor aColor)
 {
   FreeValue();
   mUnit = eUnit_Color;
   mValue.mColor = aColor;
 }
 
 void
+StyleAnimationValue::SetCurrentColorValue()
+{
+  FreeValue();
+  mUnit = eUnit_CurrentColor;
+}
+
+void
 StyleAnimationValue::SetUnparsedStringValue(const nsString& aString)
 {
   FreeValue();
   mUnit = eUnit_UnparsedString;
   mValue.mString = nsCSSValue::BufferFromString(aString).take();
 }
 
 void
@@ -4444,16 +4471,17 @@ StyleAnimationValue::operator==(const St
     return false;
   }
 
   switch (mUnit) {
     case eUnit_Null:
     case eUnit_Normal:
     case eUnit_Auto:
     case eUnit_None:
+    case eUnit_CurrentColor:
       return true;
     case eUnit_Enumerated:
     case eUnit_Visibility:
     case eUnit_Integer:
       return mValue.mInt == aOther.mValue.mInt;
     case eUnit_Coord:
       return mValue.mCoord == aOther.mValue.mCoord;
     case eUnit_Percent:
--- a/layout/style/StyleAnimationValue.h
+++ b/layout/style/StyleAnimationValue.h
@@ -266,16 +266,17 @@ public:
     eUnit_Enumerated,
     eUnit_Visibility, // special case for transitions (which converts
                       // Enumerated to Visibility as needed)
     eUnit_Integer,
     eUnit_Coord,
     eUnit_Percent,
     eUnit_Float,
     eUnit_Color,
+    eUnit_CurrentColor,
     eUnit_Calc, // nsCSSValue* (never null), always with a single
                 // calc() expression that's either length or length+percent
     eUnit_ObjectPosition, // nsCSSValue* (never null), always with a
                           // 4-entry nsCSSValue::Array
     eUnit_URL, // nsCSSValue* (never null), always with a css::URLValue
     eUnit_CSSValuePair, // nsCSSValuePair* (never null)
     eUnit_CSSValueTriplet, // nsCSSValueTriplet* (never null)
     eUnit_CSSRect, // nsCSSRect* (never null)
@@ -428,16 +429,17 @@ public:
   void SetNormalValue();
   void SetAutoValue();
   void SetNoneValue();
   void SetIntValue(int32_t aInt, Unit aUnit);
   void SetCoordValue(nscoord aCoord);
   void SetPercentValue(float aPercent);
   void SetFloatValue(float aFloat);
   void SetColorValue(nscolor aColor);
+  void SetCurrentColorValue();
   void SetUnparsedStringValue(const nsString& aString);
 
   // These setters take ownership of |aValue|, and are therefore named
   // "SetAndAdopt*".
   void SetAndAdoptCSSValueValue(nsCSSValue *aValue, Unit aUnit);
   void SetAndAdoptCSSValuePairValue(nsCSSValuePair *aValue, Unit aUnit);
   void SetAndAdoptCSSValueTripletValue(nsCSSValueTriplet *aValue, Unit aUnit);
   void SetAndAdoptCSSRectValue(nsCSSRect *aValue, Unit aUnit);
--- a/layout/style/nsStyleContext.cpp
+++ b/layout/style/nsStyleContext.cpp
@@ -1295,27 +1295,30 @@ ExtractAnimationValue(nsCSSProperty aPro
 }
 
 static nscolor
 ExtractColor(nsCSSProperty aProperty,
              nsStyleContext *aStyleContext)
 {
   StyleAnimationValue val;
   ExtractAnimationValue(aProperty, aStyleContext, val);
-  return val.GetColorValue();
+  return val.GetUnit() == StyleAnimationValue::eUnit_CurrentColor
+    ? aStyleContext->StyleColor()->mColor : val.GetColorValue();
 }
 
 static nscolor
 ExtractColorLenient(nsCSSProperty aProperty,
                     nsStyleContext *aStyleContext)
 {
   StyleAnimationValue val;
   ExtractAnimationValue(aProperty, aStyleContext, val);
   if (val.GetUnit() == StyleAnimationValue::eUnit_Color) {
     return val.GetColorValue();
+  } else if (val.GetUnit() == StyleAnimationValue::eUnit_CurrentColor) {
+    return aStyleContext->StyleColor()->mColor;
   }
   return NS_RGBA(0, 0, 0, 0);
 }
 
 struct ColorIndexSet {
   uint8_t colorIndex, alphaIndex;
 };
 
--- a/layout/style/test/test_transitions_events.html
+++ b/layout/style/test/test_transitions_events.html
@@ -17,18 +17,16 @@ https://bugzilla.mozilla.org/show_bug.cg
 #three { transition: margin 0.5s 0.25s; }
 
 #four, #five, #six, #seven::before, #seven::after {
   transition: 500ms color;
   border-color: black; /* don't derive from color */
   -moz-column-rule-color: black; /* don't derive from color */
   text-decoration-color: black; /* don't derive from color */
   outline-color: black; /* don't derive from color */
-  text-emphasis-color: black; /* don't derive from color */
-  -webkit-text-fill-color: black; /* don't derive from color */
 }
 
 #four {
   /* give the reversing transition a long duration; the reversing will
      still be quick */
   transition-duration: 30s;
   transition-timing-function: cubic-bezier(0, 1, 1, 0);
 }
@@ -70,18 +68,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_textemphasiscolor = false;
-var got_one_target_webkittextfillcolor = 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;
@@ -189,28 +185,16 @@ document.documentElement.addEventListene
         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 "text-emphasis-color":
-        ok(!got_one_target_textemphasiscolor,
-           "transitionend on one on target (text-emphasis-color)");
-        got_one_target_textemphasiscolor = true;
-        event.stopPropagation();
-        break;
-      case "-webkit-text-fill-color":
-        ok(!got_one_target_webkittextfillcolor,
-           "transitionend on one on target (-webkit-text-fill-color)");
-        got_one_target_webkittextfillcolor = 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 +
@@ -226,22 +210,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
-if (SpecialPowers.getBoolPref("layout.css.text-emphasis.enabled")) {
-  started_test(); // text-emphasis-color on #one
-}
-if (SpecialPowers.getBoolPref("layout.css.prefixes.webkit")) {
-  started_test(); // -webkit-text-fill-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
@@ -66,75 +66,84 @@ var supported_properties = {
     "-moz-box-flex": [ test_float_zeroToOne_transition,
                        test_float_aboveOne_transition,
                        test_float_zeroToOne_clamped ],
     "box-shadow": [ test_shadow_transition ],
     "-moz-column-count": [ test_pos_integer_or_auto_transition,
                            test_integer_at_least_one_clamping ],
     "-moz-column-gap": [ test_length_transition,
                          test_length_clamped ],
-    "-moz-column-rule-color": [ test_color_transition,
+    "-moz-column-rule-color": [ test_general_color_transition,
+                                test_currentcolor_transition,
                                 test_border_color_transition ],
     "-moz-column-rule-width": [ test_length_transition,
                                 test_length_clamped ],
     "-moz-column-width": [ test_length_transition,
                            test_length_clamped ],
     "-moz-image-region": [ test_rect_transition ],
     "-moz-outline-radius-bottomleft": [ test_radius_transition ],
     "-moz-outline-radius-bottomright": [ test_radius_transition ],
     "-moz-outline-radius-topleft": [ test_radius_transition ],
     "-moz-outline-radius-topright": [ test_radius_transition ],
-    "background-color": [ test_color_transition ],
+    "background-color": [ test_general_color_transition,
+                          test_currentcolor_transition ],
     "background-position": [ test_background_position_transition,
                              // FIXME: We don't currently test clamping,
                              // since background-position uses calc() as
                              // an intermediate form.
                              /* test_length_percent_pair_unclamped */ ],
     "background-size": [ test_background_size_transition,
                          // FIXME: We don't currently test clamping,
                          // since background-size uses calc() as an
                          // intermediate form.
                          /* test_length_percent_pair_clamped */ ],
-    "border-bottom-color": [ test_color_transition,
+    "border-bottom-color": [ test_general_color_transition,
+                             test_currentcolor_transition,
                              test_border_color_transition ],
     "border-bottom-width": [ test_length_transition,
                              test_length_clamped ],
-    "border-left-color": [ test_color_transition,
+    "border-left-color": [ test_general_color_transition,
+                           test_currentcolor_transition,
                            test_border_color_transition ],
     "border-left-width": [ test_length_transition,
                            test_length_clamped ],
-    "border-right-color": [ test_color_transition,
+    "border-right-color": [ test_general_color_transition,
+                            test_currentcolor_transition,
                             test_border_color_transition ],
     "border-right-width": [ test_length_transition,
                             test_length_clamped ],
     "border-spacing": [ test_length_pair_transition,
                         test_length_pair_transition_clamped ],
-    "border-top-color": [ test_color_transition,
+    "border-top-color": [ test_general_color_transition,
+                          test_currentcolor_transition,
                           test_border_color_transition ],
     "border-top-width": [ test_length_transition,
                            test_length_clamped ],
     "bottom": [ test_length_transition, test_percent_transition,
                 test_length_percent_calc_transition,
                 test_length_unclamped, test_percent_unclamped ],
     "clip": [ test_rect_transition ],
     "clip-path": [ test_clip_path_transition ],
-    "color": [ test_color_transition ],
-    "fill": [ test_color_transition ],
+    "color": [ test_general_color_transition,
+               test_currentcolor_transition ],
+    "fill": [ test_general_color_transition,
+              test_currentcolor_transition ],
     "fill-opacity" : [ test_float_zeroToOne_transition,
                        // opacity is clamped in computed style
                        // (not parsing/interpolation)
                        test_float_zeroToOne_clamped ],
     "filter" : [ test_filter_transition ],
     "flex-basis": [ test_length_transition, test_percent_transition,
                     test_length_clamped, test_percent_clamped ],
     "flex-grow": [ test_float_zeroToOne_transition,
                    test_float_aboveOne_transition ],
     "flex-shrink": [ test_float_zeroToOne_transition,
                      test_float_aboveOne_transition ],
-    "flood-color": [ test_color_transition ],
+    "flood-color": [ test_general_color_transition,
+                     test_currentcolor_transition ],
     "flood-opacity" : [ test_float_zeroToOne_transition,
                         // opacity is clamped in computed style
                         // (not parsing/interpolation)
                         test_float_zeroToOne_clamped ],
     "font-size": [ test_length_transition, test_percent_transition,
                    test_length_percent_calc_transition,
                    test_length_clamped, test_percent_clamped ],
     "font-size-adjust": [ test_float_zeroToOne_transition,
@@ -147,17 +156,18 @@ var supported_properties = {
     "grid-row-gap": [ test_grid_gap ],
     "height": [ test_length_transition, test_percent_transition,
                 test_length_percent_calc_transition,
                 test_length_clamped, test_percent_clamped ],
     "left": [ test_length_transition, test_percent_transition,
               test_length_percent_calc_transition,
               test_length_unclamped, test_percent_unclamped ],
     "letter-spacing": [ test_length_transition, test_length_unclamped ],
-    "lighting-color": [ test_color_transition ],
+    "lighting-color": [ test_general_color_transition,
+                        test_currentcolor_transition ],
     // NOTE: when calc() is supported on 'line-height', we should add
     // test_length_percent_calc_transition.
     "line-height": [ test_length_transition, test_percent_transition,
                      test_length_clamped, test_percent_clamped ],
     "margin-bottom": [ test_length_transition, test_percent_transition,
                        test_length_percent_calc_transition,
                        test_length_unclamped, test_percent_unclamped ],
     "margin-left": [ test_length_transition, test_percent_transition,
@@ -184,17 +194,18 @@ var supported_properties = {
                    test_length_percent_calc_transition,
                    test_length_clamped, test_percent_clamped ],
     "object-position": [ test_background_position_transition ],
     "opacity" : [ test_float_zeroToOne_transition,
                   // opacity is clamped in computed style
                   // (not parsing/interpolation)
                   test_float_zeroToOne_clamped ],
     "order": [ test_integer_transition ],
-    "outline-color": [ test_color_transition ],
+    "outline-color": [ test_general_color_transition,
+                       test_currentcolor_transition ],
     "outline-offset": [ test_length_transition, test_length_unclamped ],
     "outline-width": [ test_length_transition, test_length_clamped ],
     "padding-bottom": [ test_length_transition, test_percent_transition,
                         test_length_percent_calc_transition,
                         test_length_clamped, test_percent_clamped ],
     "padding-left": [ test_length_transition, test_percent_transition,
                       test_length_percent_calc_transition,
                       test_length_clamped, test_percent_clamped ],
@@ -206,43 +217,46 @@ var supported_properties = {
                      test_length_clamped, test_percent_clamped ],
     "perspective": [ test_length_transition ],
     "perspective-origin": [ test_length_pair_transition,
                             test_length_percent_pair_transition,
                             test_length_percent_pair_unclamped ],
     "right": [ test_length_transition, test_percent_transition,
                test_length_percent_calc_transition,
                test_length_unclamped, test_percent_unclamped ],
-    "stop-color": [ test_color_transition ],
+    "stop-color": [ test_general_color_transition,
+                    test_currentcolor_transition ],
     "stop-opacity" : [ test_float_zeroToOne_transition,
                        // opacity is clamped in computed style
                        // (not parsing/interpolation)
                        test_float_zeroToOne_clamped ],
-    "stroke": [ test_color_transition ],
+    "stroke": [ test_general_color_transition,
+                test_currentcolor_transition ],
     "stroke-dasharray": [ test_dasharray_transition ],
     // NOTE: when calc() is supported on 'stroke-dashoffset', we should
     // add test_length_percent_calc_transition.
     "stroke-dashoffset": [ test_length_transition_svg, test_percent_transition,
                            test_length_unclamped_svg, test_percent_unclamped ],
     "stroke-miterlimit": [ test_float_aboveOne_transition,
                            test_float_aboveOne_clamped ],
     "stroke-opacity" : [ test_float_zeroToOne_transition,
                          // opacity is clamped in computed style
                          // (not parsing/interpolation)
                          test_float_zeroToOne_clamped ],
     // 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,
+    "text-decoration": [ test_general_color_shorthand_transition,
+                         test_currentcolor_shorthand_transition,
                          test_border_color_shorthand_transition ],
-    "text-decoration-color": [ test_color_transition,
+    "text-decoration-color": [ test_general_color_transition,
+                               test_currentcolor_transition,
                                test_border_color_transition ],
-    "text-emphasis-color": [ test_color_transition,
-                             test_border_color_transition ],
+    "text-emphasis-color": [ test_general_color_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,
              test_length_unclamped, test_percent_unclamped ],
     "transform": [ test_transform_transition ],
@@ -253,18 +267,17 @@ var supported_properties = {
                         test_length_percent_calc_transition,
                         test_length_unclamped, test_percent_unclamped ],
     "visibility": [ test_visibility_transition ],
     "width": [ test_length_transition, test_percent_transition,
                test_length_percent_calc_transition,
                test_length_clamped, test_percent_clamped ],
     "word-spacing": [ test_length_transition, test_length_unclamped ],
     "z-index": [ test_integer_transition, test_pos_integer_or_auto_transition ],
-    "-webkit-text-fill-color": [ test_color_transition,
-                                 test_border_color_transition ]
+    "-webkit-text-fill-color": [ test_general_color_transition ]
 };
 
 if (SupportsMaskShorthand()) {
   supported_properties["mask-position"] = [ test_background_position_transition,
                                      // FIXME: We don't currently test clamping,
                                      // since mask-position uses calc() as
                                      // an intermediate form.
                                      /* test_length_percent_pair_unclamped */ ];
@@ -1220,46 +1233,31 @@ function test_length_percent_calc_transi
 
   check_distance(prop, "50%", "calc(37.5% + 50px)", "200px");
   check_distance(prop, "calc(25% + 100px)", "calc(37.5% + 75px)",
                        "75%");
   check_distance(prop, "150px", "calc(125px + 12.5%)",
                        "calc(50% + 50px)");
 }
 
-function test_color_transition(prop, get_color=(x => x), is_shorthand=false) {
+function test_general_color_transition(prop, get_color=(x => x), is_shorthand=false) {
   div.style.setProperty("transition-property", "none", "");
   div.style.setProperty(prop, "rgb(255, 28, 0)", "");
   is(get_color(cs.getPropertyValue(prop)), "rgb(255, 28, 0)",
      "color-valued property " + prop + ": computed value before transition");
   div.style.setProperty("transition-property", prop, "");
   div.style.setProperty(prop, "rgb(75, 84, 128)", "");
   is(get_color(cs.getPropertyValue(prop)), "rgb(210, 42, 32)",
      "color-valued property " + prop + ": interpolation of colors");
 
-  div.style.setProperty("transition-property", "none", "");
-  div.style.setProperty(prop, "rgb(128, 64, 0)", "");
-  (prop == "color" ? div.parentNode : div).style.
-    setProperty("color", "rgb(0, 0, 128)", "");
-  is(get_color(cs.getPropertyValue(prop)), "rgb(128, 64, 0)",
-     "color-valued property " + prop + ": computed value before transition");
-  div.style.setProperty("transition-property", prop, "");
-  div.style.setProperty(prop, "currentColor", "");
-  is(get_color(cs.getPropertyValue(prop)), "rgb(96, 48, 32)",
-     "color-valued property " + prop + ": interpolation of currentColor");
-
   if (!is_shorthand) {
     check_distance(prop, "rgb(255, 28, 0)", "rgb(210, 42, 32)",
                          "rgb(75, 84, 128)");
-    check_distance(prop, "rgb(128, 64, 0)", "rgb(96, 48, 32)",
-                         "currentColor");
   }
 
-  (prop == "color" ? div.parentNode : div).style.removeProperty("color");
-
   div.style.setProperty("transition-timing-function", FUNC_NEGATIVE, "");
   div.style.setProperty("transition-property", "none", "");
   div.style.setProperty(prop, "rgb(0, 255, 0)", "");
   var vals = cs.getPropertyValue(prop).match(/rgb\(([^, ]*), ([^, ]*), ([^, ]*)\)/);
   is(vals.length, 4,
      "color-valued property " + prop + ": flush before clamping test (length)");
   is(vals[1], "0",
      "color-valued property " + prop + ": flush before clamping test (red)");
@@ -1277,16 +1275,36 @@ function test_color_transition(prop, get
      "color-valued property " + prop + ": clamping of negatives (red)");
   is(vals[2], "255",
      "color-valued property " + prop + ": clamping of above-range (green)");
   is(vals[3], "0",
      "color-valued property " + prop + ": clamping of negatives (blue)");
   div.style.setProperty("transition-timing-function", "linear", "");
 }
 
+function test_currentcolor_transition(prop, get_color=(x => x), is_shorthand=false) {
+  div.style.setProperty("transition-property", "none", "");
+  div.style.setProperty(prop, "rgb(128, 64, 0)", "");
+  (prop == "color" ? div.parentNode : div).style.
+    setProperty("color", "rgb(0, 0, 128)", "");
+  is(get_color(cs.getPropertyValue(prop)), "rgb(128, 64, 0)",
+     "color-valued property " + prop + ": computed value before transition");
+  div.style.setProperty("transition-property", prop, "");
+  div.style.setProperty(prop, "currentColor", "");
+  is(get_color(cs.getPropertyValue(prop)), "rgb(96, 48, 32)",
+     "color-valued property " + prop + ": interpolation of currentColor");
+
+  if (!is_shorthand) {
+    check_distance(prop, "rgb(128, 64, 0)", "rgb(96, 48, 32)",
+                         "currentColor");
+  }
+
+  (prop == "color" ? div.parentNode : div).style.removeProperty("color");
+}
+
 function test_border_color_transition(prop, get_color=(x => x), is_shorthand=false) {
   div.style.setProperty("transition-property", "none", "");
   div.style.setProperty(prop, "rgb(128, 64, 0)", "");
   div.style.setProperty("color", "rgb(0, 0, 128)", "");
   is(get_color(cs.getPropertyValue(prop)), "rgb(128, 64, 0)",
      "color-valued property " + prop + ": computed value before transition");
   div.style.setProperty("transition-property", prop, "");
   div.style.removeProperty(prop);
@@ -1301,18 +1319,22 @@ function test_border_color_transition(pr
 }
 
 function get_color_from_shorthand_value(value) {
   var m = value.match(/rgb\([^, ]*, [^, ]*, [^, ]*\)/);
   isnot(m, null, "shorthand property value should contain color");
   return m[0];
 }
 
-function test_color_shorthand_transition(prop) {
-  test_color_transition(prop, get_color_from_shorthand_value, true);
+function test_general_color_shorthand_transition(prop) {
+  test_general_color_transition(prop, get_color_from_shorthand_value, true);
+}
+
+function test_currentcolor_shorthand_transition(prop) {
+  test_currentcolor_transition(prop, get_color_from_shorthand_value, true);
 }
 
 function test_border_color_shorthand_transition(prop) {
   test_border_color_transition(prop, get_color_from_shorthand_value, true);
 }
 
 function test_clip_path_equals(computedValStr, expectedList)
 {