Bug 1299741 part 9 - Implement interpolation between numeric color and currentcolor. r=birtles draft
authorXidorn Quan <me@upsuper.org>
Fri, 16 Sep 2016 14:44:09 +1000
changeset 415368 ba7be3894c152aeed3de30c8050423303636a42e
parent 415367 2582ce0e1a665701958f3647d871d8febe7f93fb
child 415369 855783009cb8a8c800504299c53055634dbc66bd
push id29862
push userxquan@mozilla.com
push dateTue, 20 Sep 2016 08:44:59 +0000
reviewersbirtles
bugs1299741
milestone52.0a1
Bug 1299741 part 9 - Implement interpolation between numeric color and currentcolor. r=birtles MozReview-Commit-ID: DuB6FZYveXE
layout/style/StyleAnimationValue.cpp
layout/style/nsCSSProps.h
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -65,16 +65,25 @@ GetCommonUnit(nsCSSPropertyID aProperty,
          aFirstUnit == StyleAnimationValue::eUnit_Percent ||
          aFirstUnit == StyleAnimationValue::eUnit_Calc) &&
         (aSecondUnit == StyleAnimationValue::eUnit_Coord ||
          aSecondUnit == StyleAnimationValue::eUnit_Percent ||
          aSecondUnit == StyleAnimationValue::eUnit_Calc)) {
       // We can use calc() as the common unit.
       return StyleAnimationValue::eUnit_Calc;
     }
+    if ((aFirstUnit == StyleAnimationValue::eUnit_Color ||
+         aFirstUnit == StyleAnimationValue::eUnit_CurrentColor ||
+         aFirstUnit == StyleAnimationValue::eUnit_ComplexColor) &&
+        (aSecondUnit == StyleAnimationValue::eUnit_Color ||
+         aSecondUnit == StyleAnimationValue::eUnit_CurrentColor ||
+         aSecondUnit == StyleAnimationValue::eUnit_ComplexColor)) {
+      // We can use complex color as the common unit.
+      return StyleAnimationValue::eUnit_ComplexColor;
+    }
     return StyleAnimationValue::eUnit_Null;
   }
   return aFirstUnit;
 }
 
 static
 nsCSSUnit
 GetCommonUnit(nsCSSPropertyID aProperty,
@@ -513,16 +522,32 @@ static RGBAColorData
 ExtractColor(const StyleAnimationValue& aValue)
 {
   MOZ_ASSERT(aValue.GetUnit() == StyleAnimationValue::eUnit_Color);
   nsCSSValue* value = aValue.GetCSSValueValue();
   MOZ_ASSERT(value, "CSS value must be valid");
   return ExtractColor(*value);
 }
 
+static ComplexColorData
+ExtractComplexColor(const StyleAnimationValue& aValue)
+{
+  switch (aValue.GetUnit()) {
+    case StyleAnimationValue::eUnit_Color:
+      return ComplexColorData(ExtractColor(aValue), 0.0f);
+    case StyleAnimationValue::eUnit_CurrentColor:
+      return ComplexColorData({0, 0, 0, 0}, 1.0f);
+    case StyleAnimationValue::eUnit_ComplexColor:
+      return ComplexColorData(aValue.GetComplexColorData());
+    default:
+      MOZ_ASSERT_UNREACHABLE("Unknown unit");
+      return ComplexColorData({0, 0, 0, 0}, 0.0f);
+  }
+}
+
 double
 StyleAnimationValue::ComputeColorDistance(const RGBAColorData& aStartColor,
                                           const RGBAColorData& aEndColor)
 {
   // http://www.w3.org/TR/smil-animation/#animateColorElement says
   // that we should use Euclidean RGB cube distance.  However, we
   // have to extend that to RGBA.  For now, we'll just use the
   // Euclidean distance in the (part of the) 4-cube of premultiplied
@@ -554,17 +579,16 @@ 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:
     case eUnit_DiscreteCSSValue:
       return false;
 
     case eUnit_Enumerated:
       switch (aProperty) {
         case eCSSProperty_font_stretch: {
           // just like eUnit_Integer.
           int32_t startInt = aStartValue.GetIntValue();
@@ -613,16 +637,41 @@ StyleAnimationValue::ComputeDistance(nsC
       aDistance = Abs(double(endFloat) - double(startFloat));
       return true;
     }
     case eUnit_Color: {
       aDistance = ComputeColorDistance(ExtractColor(aStartValue),
                                        ExtractColor(aEndValue));
       return true;
     }
+    case eUnit_CurrentColor: {
+      aDistance = 0;
+      return true;
+    }
+    case eUnit_ComplexColor: {
+      ComplexColorData color1 = ExtractComplexColor(aStartValue);
+      ComplexColorData color2 = ExtractComplexColor(aEndValue);
+      // Common case is interpolating between a color and a currentcolor
+      if (color1.IsNumericColor() && color2.IsCurrentColor()) {
+        double dist = ComputeColorDistance(color1.mColor, NS_RGBA(0, 0, 0, 0));
+        aDistance = sqrt(dist * dist + 1);
+        return true;
+      }
+      if (color1.IsCurrentColor() && color2.IsNumericColor()) {
+        double dist = ComputeColorDistance(NS_RGBA(0, 0, 0, 0), color2.mColor);
+        aDistance = sqrt(dist * dist + 1);
+        return true;
+      }
+      // If we ever reach here, we may want to use the code in
+      // bug 1299741 comment 79 to compute it.
+      MOZ_ASSERT_UNREACHABLE("We shouldn't get here as we only call "
+                             "ComputeDistance on pre-interpolation values");
+      aDistance = 0.0;
+      return true;
+    }
     case eUnit_Calc: {
       PixelCalcValue v1 = ExtractCalcValue(aStartValue);
       PixelCalcValue v2 = ExtractCalcValue(aEndValue);
       float difflen = v2.mLength - v1.mLength;
       float diffpct = v2.mPercent - v1.mPercent;
       aDistance = sqrt(difflen * difflen + diffpct * diffpct);
       return true;
     }
@@ -2433,17 +2482,16 @@ 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:
     case eUnit_DiscreteCSSValue:
       return false;
 
     case eUnit_Enumerated:
       switch (aProperty) {
         case eCSSProperty_font_stretch: {
           // Animate just like eUnit_Integer.
           int32_t result = floor(aCoeff1 * double(aValue1.GetIntValue()) +
@@ -2518,16 +2566,48 @@ StyleAnimationValue::AddWeighted(nsCSSPr
       RGBAColorData color1 = ExtractColor(aValue1);
       RGBAColorData color2 = ExtractColor(aValue2);
       auto resultColor = MakeUnique<nsCSSValue>();
       resultColor->SetColorValue(
         AddWeightedColorsAndClamp(aCoeff1, color1, aCoeff2, color2));
       aResultValue.SetAndAdoptCSSValueValue(resultColor.release(), eUnit_Color);
       return true;
     }
+    case eUnit_CurrentColor: {
+      aResultValue.SetCurrentColorValue();
+      return true;
+    }
+    case eUnit_ComplexColor: {
+      ComplexColorData color1 = ExtractComplexColor(aValue1);
+      ComplexColorData color2 = ExtractComplexColor(aValue2);
+      RefPtr<ComplexColorValue> result = new ComplexColorValue;
+      // Common case is interpolating between a color and a currentcolor.
+      if (color1.IsNumericColor() && color2.IsCurrentColor()) {
+        result->mColor = color1.mColor;
+        result->mForegroundRatio = aCoeff2;
+      } else if (color1.IsCurrentColor() && color2.IsNumericColor()) {
+        result->mColor = color2.mColor;
+        result->mForegroundRatio = aCoeff1;
+      } else {
+        float ratio1 = 1.0f - color1.mForegroundRatio;
+        float ratio2 = 1.0f - color2.mForegroundRatio;
+        float alpha1 = color1.mColor.mA * ratio1;
+        float alpha2 = color2.mColor.mA * ratio2;
+        RGBAColorData resultColor =
+          AddWeightedColors(aCoeff1, color1.mColor.WithAlpha(alpha1),
+                            aCoeff2, color2.mColor.WithAlpha(alpha2));
+        float resultRatio = color1.mForegroundRatio * aCoeff1 +
+                            color2.mForegroundRatio * aCoeff2;
+        float resultAlpha = resultColor.mA / (1.0f - resultRatio);
+        result->mColor = resultColor.WithAlpha(resultAlpha);
+        result->mForegroundRatio = resultRatio;
+      }
+      aResultValue.SetComplexColorValue(result.forget());
+      return true;
+    }
     case eUnit_Calc: {
       PixelCalcValue v1 = ExtractCalcValue(aValue1);
       PixelCalcValue v2 = ExtractCalcValue(aValue2);
       double len = aCoeff1 * v1.mLength + aCoeff2 * v2.mLength;
       double pct = aCoeff1 * v1.mPercent + aCoeff2 * v2.mPercent;
       bool hasPct = (aCoeff1 != 0.0 && v1.mHasPercent) ||
                       (aCoeff2 != 0.0 && v2.mHasPercent);
       nsCSSValue *val = new nsCSSValue();
@@ -4285,16 +4365,21 @@ StyleAnimationValue::ExtractComputedValu
         // interpolation with it.
         aComputedValue.SetNoneValue();
       }
       return true;
     case eStyleAnimType_Color:
       aComputedValue.SetColorValue(
         StyleDataAtOffset<nscolor>(styleStruct, ssOffset));
       return true;
+    case eStyleAnimType_ComplexColor: {
+      aComputedValue.SetComplexColorValue(
+        StyleDataAtOffset<StyleComplexColor>(styleStruct, ssOffset));
+      return true;
+    }
     case eStyleAnimType_PaintServer: {
       const nsStyleSVGPaint& paint =
         StyleDataAtOffset<nsStyleSVGPaint>(styleStruct, ssOffset);
       if (paint.mType == eStyleSVGPaintType_Color) {
         aComputedValue.SetColorValue(paint.mPaint.mColor);
         return true;
       }
       if (paint.mType == eStyleSVGPaintType_Server) {
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -310,16 +310,19 @@ enum nsStyleAnimType {
   eStyleAnimType_nscoord,
 
   // float values
   eStyleAnimType_float,
 
   // nscolor values
   eStyleAnimType_Color,
 
+  // StyleComplexColor values
+  eStyleAnimType_ComplexColor,
+
   // nsStyleSVGPaint values
   eStyleAnimType_PaintServer,
 
   // RefPtr<nsCSSShadowArray> values
   eStyleAnimType_Shadow,
 
   // discrete values
   eStyleAnimType_Discrete,