Bug 1216843 - Part 7: Implement color accumulation. r=dholbert
authorHiroyuki Ikezoe <hiikezoe@mozilla-japan.org>
Tue, 13 Sep 2016 11:48:45 +0900
changeset 357142 8bef6bb7442c95e31ebe6217a15698c8c2f820ec
parent 357141 8c1631ef0ad9d31c59a02a0a6fc26968414ea376
child 357143 9900b2f32860efbf5d4f6c9df1bb37e0e403e090
push id1324
push usermtabara@mozilla.com
push dateMon, 16 Jan 2017 13:07:44 +0000
treeherdermozilla-release@a01c49833940 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1216843
milestone51.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1216843 - Part 7: Implement color accumulation. r=dholbert MozReview-Commit-ID: Ic7dIrZWvih
layout/style/StyleAnimationValue.cpp
testing/web-platform/meta/web-animations/interfaces/KeyframeEffect/iterationComposite.html.ini
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -1187,19 +1187,28 @@ GetPremultipliedColorComponents(const ns
   nscolor color = aValue.GetColorValue();
   double alpha = NS_GET_A(color) * (1.0 / 255.0);
   return MakeTuple(NS_GET_R(color) * alpha,
                    NS_GET_G(color) * alpha,
                    NS_GET_B(color) * alpha,
                    alpha);
 }
 
+enum class ColorAdditionType {
+  Clamped, // Clamp each color channel after adding.
+  Unclamped // Do not clamp color channels after adding.
+};
+
+// |aAdditionType| should be Clamped in case of interpolation or SMIL
+// animation (e.g. 'by' attribute). For now, Unclamped is only for
+// accumulation.
 static void
 AddWeightedColors(double aCoeff1, const nsCSSValue& aValue1,
                   double aCoeff2, const nsCSSValue& aValue2,
+                  ColorAdditionType aAdditionType,
                   nsCSSValue& aResult)
 {
   MOZ_ASSERT(aValue1.IsNumericColorUnit() && aValue2.IsNumericColorUnit(),
              "The unit should be color");
   // FIXME (spec): The CSS transitions spec doesn't say whether
   // colors are premultiplied, but things work better when they are,
   // so use premultiplication.  Spec issue is still open per
   // http://lists.w3.org/Archives/Public/www-style/2009Jul/0050.html
@@ -1217,21 +1226,33 @@ AddWeightedColors(double aCoeff1, const 
     return;
   }
 
   if (Aresf > 1.0) {
     Aresf = 1.0;
   }
 
   double factor = 1.0 / Aresf;
-  uint8_t Ares = NSToIntRound(Aresf * 255.0);
-  uint8_t Rres = ClampColor((R1 * aCoeff1 + R2 * aCoeff2) * factor);
-  uint8_t Gres = ClampColor((G1 * aCoeff1 + G2 * aCoeff2) * factor);
-  uint8_t Bres = ClampColor((B1 * aCoeff1 + B2 * aCoeff2) * factor);
-  aResult.SetColorValue(NS_RGBA(Rres, Gres, Bres, Ares));
+  double Rres = (R1 * aCoeff1 + R2 * aCoeff2) * factor;
+  double Gres = (G1 * aCoeff1 + G2 * aCoeff2) * factor;
+  double Bres = (B1 * aCoeff1 + B2 * aCoeff2) * factor;
+
+  if (aAdditionType == ColorAdditionType::Clamped) {
+    aResult.SetColorValue(
+      NS_RGBA(ClampColor(Rres), ClampColor(Gres), ClampColor(Bres),
+              NSToIntRound(Aresf * 255.0)));
+    return;
+  }
+
+  Rres = Rres * (1.0 / 255.0);
+  Gres = Gres * (1.0 / 255.0);
+  Bres = Bres * (1.0 / 255.0);
+
+  aResult.SetFloatColorValue(Rres, Gres, Bres, Aresf,
+                             eCSSUnit_PercentageRGBAColor);
 }
 
 // Multiplies |aValue| color by |aDilutionRation| with premultiplication.
 // The result is stored in |aResult|.
 // (The logic here should pretty closely match AddWeightedColors()' logic.)
 static void
 DiluteColor(const nsCSSValue& aValue, double aDilutionRatio,
             nsCSSValue& aResult)
@@ -1277,28 +1298,33 @@ AddShadowItems(double aCoeff1, const nsC
                      // blur radius must be nonnegative
                      (i == 2) ? CSS_PROPERTY_VALUE_NONNEGATIVE : 0);
   }
 
   const nsCSSValue& color1 = array1->Item(4);
   const nsCSSValue& color2 = array2->Item(4);
   const nsCSSValue& inset1 = array1->Item(5);
   const nsCSSValue& inset2 = array2->Item(5);
-  if (color1.GetUnit() != color2.GetUnit() ||
+  if ((color1.GetUnit() != color2.GetUnit() &&
+       (!color1.IsNumericColorUnit() || !color2.IsNumericColorUnit())) ||
       inset1.GetUnit() != inset2.GetUnit()) {
     // We don't know how to animate between color and no-color, or
     // between inset and not-inset.
+    // NOTE: In case when both colors' units are eCSSUnit_Null, that means
+    // neither color value was specified, so we can interpolate.
     return false;
   }
 
   if (color1.GetUnit() != eCSSUnit_Null) {
     if (aCoeff2 == 0.0 && aCoeff1 != 1.0) {
       DiluteColor(color1, aCoeff1, resultArray->Item(4));
     } else {
-      AddWeightedColors(aCoeff1, color1, aCoeff2, color2, resultArray->Item(4));
+      AddWeightedColors(aCoeff1, color1, aCoeff2, color2,
+                        ColorAdditionType::Clamped,
+                        resultArray->Item(4));
     }
   }
 
   MOZ_ASSERT(inset1 == inset2, "should match");
   resultArray->Item(5) = inset1;
 
   nsCSSValueList *resultItem = new nsCSSValueList;
   resultItem->mValue.SetArrayValue(resultArray, eCSSUnit_Array);
@@ -2442,17 +2468,19 @@ StyleAnimationValue::AddWeighted(nsCSSPr
       // We are using AddWeighted() with a zero aCoeff2 for colors to
       // pretend AddWeighted() against transparent color, i.e. rgba(0, 0, 0, 0).
       // But unpremultiplication in AddWeightedColors() does not work well
       // for such cases, so we use another function named DiluteColor() which
       // has a similar logic to AddWeightedColors().
       if (aCoeff2 == 0.0) {
         DiluteColor(*value1, aCoeff1, *resultColor);
       } else {
-        AddWeightedColors(aCoeff1, *value1, aCoeff2, *value2, *resultColor);
+        AddWeightedColors(aCoeff1, *value1, aCoeff2, *value2,
+                          ColorAdditionType::Clamped,
+                          *resultColor);
       }
       aResultValue.SetAndAdoptCSSValueValue(resultColor.release(), eUnit_Color);
       return true;
     }
     case eUnit_Calc: {
       PixelCalcValue v1 = ExtractCalcValue(aValue1);
       PixelCalcValue v2 = ExtractCalcValue(aValue2);
       double len = aCoeff1 * v1.mLength + aCoeff2 * v2.mLength;
@@ -2833,19 +2861,30 @@ StyleAnimationValue::Accumulate(nsCSSPro
                                 StyleAnimationValue& aDest,
                                 const StyleAnimationValue& aValueToAccumulate,
                                 uint64_t aCount)
 {
   Unit commonUnit =
     GetCommonUnit(aProperty, aDest.GetUnit(), aValueToAccumulate.GetUnit());
   switch (commonUnit) {
     // FIXME: implement them!
-    //case eUnit_Color:
     //case eUnit_Shadow:
     //case eUnit_Filter:
+    case eUnit_Color: {
+      auto resultColor = MakeUnique<nsCSSValue>();
+      AddWeightedColors(1.0,
+                        *aDest.GetCSSValueValue(),
+                        aCount,
+                        *aValueToAccumulate.GetCSSValueValue(),
+                        ColorAdditionType::Unclamped,
+                        *resultColor);
+
+      aDest.SetAndAdoptCSSValueValue(resultColor.release(), eUnit_Color);
+      return true;
+    }
     default:
       return Add(aProperty, aDest, aValueToAccumulate, aCount);
   }
   MOZ_ASSERT_UNREACHABLE("Can't accumulate using the given common unit");
   return false;
 }
 
 already_AddRefed<css::StyleRule>
--- a/testing/web-platform/meta/web-animations/interfaces/KeyframeEffect/iterationComposite.html.ini
+++ b/testing/web-platform/meta/web-animations/interfaces/KeyframeEffect/iterationComposite.html.ini
@@ -1,11 +1,8 @@
 [iterationComposite.html]
   type: testharness
-  [iterationComposite of <color> type animation]
-    expected: FAIL
-
   [iterationComposite of filter drop-shadow animation]
     expected: FAIL
 
   [iterationComposite of box-shadow animation]
     expected: FAIL