Bug 1286151 - Part 1: Implement filter distance for blur. draft
authorBoris Chiou <boris.chiou@gmail.com>
Thu, 10 Nov 2016 15:15:52 +0800
changeset 440277 d46dd2baeeb6e8c14a0e92577bb6e0337bed2f1e
parent 435666 783356f1476eafd8e4d6fa5f3919cf6167e84f8d
child 440278 7777d595c7d52db25c87152fb2f9d8db5e0c1178
push id36192
push userbmo:boris.chiou@gmail.com
push dateThu, 17 Nov 2016 07:51:48 +0000
bugs1286151
milestone52.0a1
Bug 1286151 - Part 1: Implement filter distance for blur. MozReview-Commit-ID: 44EP55V8ldg
layout/style/StyleAnimationValue.cpp
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -728,16 +728,138 @@ StyleAnimationValue::ComputeColorDistanc
 
   double diffA = startA - endA;
   double diffR = startR - endR;
   double diffG = startG - endG;
   double diffB = startB - endB;
   return sqrt(diffA * diffA + diffR * diffR + diffG * diffG + diffB * diffB);
 }
 
+enum class ColorAdditionType {
+  Clamped, // Clamp each color channel after adding.
+  Unclamped // Do not clamp color channels after adding.
+};
+
+static UniquePtr<nsCSSValueList>
+AddWeightedFilterFunction(double aCoeff1, const nsCSSValueList* aList1,
+                          double aCoeff2, const nsCSSValueList* aList2,
+                          ColorAdditionType aColorAdditionType);
+
+// Return false if we cannot compute the distance between these filter
+// functions.
+static bool
+ComputeFilterDistance(const nsCSSValueList* aList1,
+                      const nsCSSValueList* aList2,
+                      double& aSquareDistance)
+{
+  MOZ_ASSERT(aList1, "expected filter list");
+  MOZ_ASSERT(aList2, "expected filter list");
+  MOZ_ASSERT(aList1->mValue.GetUnit() == eCSSUnit_Function,
+             "expected function");
+  MOZ_ASSERT(aList2->mValue.GetUnit() == eCSSUnit_Function,
+             "expected function");
+
+  RefPtr<nsCSSValue::Array> a1 = aList1->mValue.GetArrayValue();
+  RefPtr<nsCSSValue::Array> a2 = aList2->mValue.GetArrayValue();
+  nsCSSKeyword filterFunction = a1->Item(0).GetKeywordValue();
+  if (filterFunction != a2->Item(0).GetKeywordValue()) {
+    return false;
+  }
+
+  const nsCSSValue& func1 = a1->Item(1);
+  const nsCSSValue& func2 = a2->Item(1);
+  switch (filterFunction) {
+    case eCSSKeyword_blur: {
+      nsCSSValue diff;
+      // In AddWeightedFilterFunctionImpl, blur may have different units, so we
+      // use eCSSUnit_Calc for that case.
+      if (!AddCSSValuePixelPercentCalc(0,
+                                       func1.GetUnit() == func2.GetUnit()
+                                         ? func1.GetUnit()
+                                         : eCSSUnit_Calc,
+                                       1.0, func2,
+                                       -1.0, func1,
+                                       diff)) {
+        return false;
+      }
+      // ExtractCalcValue makes sure mHasPercent and mPercent are correct.
+      PixelCalcValue v = ExtractCalcValue(diff);
+      aSquareDistance = v.mLength * v.mLength + v.mPercent * v.mPercent;
+      break;
+    }
+    case eCSSKeyword_grayscale:
+    case eCSSKeyword_invert:
+    case eCSSKeyword_sepia:
+    case eCSSKeyword_brightness:
+    case eCSSKeyword_contrast:
+    case eCSSKeyword_opacity:
+    case eCSSKeyword_saturate:
+      // TODO
+      break;
+    case eCSSKeyword_hue_rotate:
+      // TODO
+      break;
+    case eCSSKeyword_drop_shadow:
+      // TODO
+      break;
+    default:
+      MOZ_ASSERT_UNREACHABLE("unknown filter function");
+      return false;
+  }
+  return true;
+}
+
+static bool
+ComputeFilterListDistance(const nsCSSValueList* aList1,
+                          const nsCSSValueList* aList2,
+                          double& aDistance)
+{
+  double squareDistance = 0.0;
+  while (aList1 || aList2) {
+    // Return false if one of the lists is neither none nor a function.
+    if ((aList1 && aList1->mValue.GetUnit() != eCSSUnit_Function) ||
+        (aList2 && aList2->mValue.GetUnit() != eCSSUnit_Function)) {
+      return false;
+    }
+
+    MOZ_ASSERT(aList1 || aList2, "one function list item must not be null");
+
+    double currentSquareDistance = 0.0;
+    if (!aList1) {
+      // This is a tricky to get an equivalent none filter function by 0.0
+      // coefficients. Although we don't guarantee this function can get the
+      // correct default values, it can reuse the code from the interpolation.
+      UniquePtr<nsCSSValueList> none =
+        AddWeightedFilterFunction(0, aList2, 0, aList2,
+                                  ColorAdditionType::Clamped);
+      if (!ComputeFilterDistance(none.get(), aList2, currentSquareDistance)) {
+        return false;
+      }
+      aList2 = aList2->mNext;
+    } else if (!aList2) {
+      UniquePtr<nsCSSValueList> none =
+        AddWeightedFilterFunction(0, aList1, 0, aList1,
+                                  ColorAdditionType::Clamped);
+      if (!ComputeFilterDistance(aList1, none.get(), currentSquareDistance)) {
+        return false;
+      }
+      aList1 = aList1->mNext;
+    } else {
+      if (!ComputeFilterDistance(aList1, aList2, currentSquareDistance)) {
+        return false;
+      }
+      aList1 = aList1->mNext;
+      aList2 = aList2->mNext;
+    }
+    squareDistance += currentSquareDistance;
+  }
+  aDistance = sqrt(squareDistance);
+  return true;
+}
+
 enum class Restrictions {
   Enable,
   Disable
 };
 
 static already_AddRefed<nsCSSValue::Array>
 AddShapeFunction(nsCSSPropertyID aProperty,
                  double aCoeff1, const nsCSSValue::Array* aArray1,
@@ -1503,18 +1625,21 @@ StyleAnimationValue::ComputeDistance(nsC
     }
     case eUnit_Shape:
       aDistance = ComputeShapeDistance(aProperty,
                                        aStartValue.GetCSSValueArrayValue(),
                                        aEndValue.GetCSSValueArrayValue());
       return true;
 
     case eUnit_Filter:
-      // Bug 1286151: Support paced animations for filter function
-      // interpolation.
+      ComputeFilterListDistance(aStartValue.GetCSSValueListValue(),
+                                aEndValue.GetCSSValueListValue(),
+                                aDistance);
+      // TODO: Remove the setting and return true in the later patch.
+      aDistance = 0.0;
       return false;
 
     case eUnit_Transform: {
       // FIXME: We don't have an official spec to define the distance of
       // two transform lists, but paced spacing (defined in Web Animations API)
       // needs this, so we implement this according to the concept of the
       // interpolation of two transform lists.
       // Issue: https://www.w3.org/TR/web-animations-1/#issue-789f9fd1
@@ -1684,21 +1809,16 @@ AddCSSValuePercentNumber(const uint32_t 
   // aCoeff2 is 0, then we'll return the value halfway between 1 and
   // aValue1, rather than the value halfway between 0 and aValue1.
   // Note that we do something similar in AddTransformScale().
   float result = (n1 - aInitialVal) * aCoeff1 + (n2 - aInitialVal) * aCoeff2;
   aResult.SetFloatValue(RestrictValue(aValueRestrictions, result + aInitialVal),
                         eCSSUnit_Number);
 }
 
-enum class ColorAdditionType {
-  Clamped, // Clamp each color channel after adding.
-  Unclamped // Do not clamp color channels after adding.
-};
-
 // Unclamped AddWeightedColors.
 static RGBAColorData
 AddWeightedColors(double aCoeff1, const RGBAColorData& aValue1,
                   double aCoeff2, const RGBAColorData& aValue2)
 {
   float factor1 = aValue1.mA * aCoeff1;
   float factor2 = aValue2.mA * aCoeff2;
   float resultA = factor1 + factor2;