Bug 1286150 - Part 3: Implement shape distance for circle and ellipse.
MozReview-Commit-ID: EX4C4IM0nVx
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -728,16 +728,83 @@ 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 Restrictions {
+ Enable,
+ Disable
+};
+
+static already_AddRefed<nsCSSValue::Array>
+AddShapeFunction(nsCSSPropertyID aProperty,
+ double aCoeff1, const nsCSSValue::Array* aArray1,
+ double aCoeff2, const nsCSSValue::Array* aArray2,
+ Restrictions aRestriction = Restrictions::Enable);
+
+static double
+ComputeShapeDistance(nsCSSPropertyID aProperty,
+ const nsCSSValue::Array* aArray1,
+ const nsCSSValue::Array* aArray2)
+{
+ // Use AddShapeFunction to get the difference between two shape functions.
+ RefPtr<nsCSSValue::Array> diffShape =
+ AddShapeFunction(aProperty, 1.0, aArray2, -1.0, aArray1,
+ Restrictions::Disable);
+ if (!diffShape) {
+ return 0.0;
+ }
+
+ // A helper function to convert a calc() diff value into a double distance.
+ auto pixelCalcDistance = [](const PixelCalcValue& aValue) {
+ MOZ_ASSERT(aValue.mHasPercent || aValue.mPercent == 0.0f,
+ "can't have a nonzero percentage part without having percentages");
+ return aValue.mLength * aValue.mLength + aValue.mPercent * aValue.mPercent;
+ };
+
+ double squareDistance = 0.0;
+ const nsCSSValue::Array* func = diffShape->Item(0).GetArrayValue();
+ nsCSSKeyword shapeFuncName = func->Item(0).GetKeywordValue();
+ switch (shapeFuncName) {
+ case eCSSKeyword_ellipse:
+ case eCSSKeyword_circle: {
+ // Skip the first element which is the function keyword.
+ // Also, skip the last element which is an array for <position>
+ const size_t len = func->Count();
+ for (size_t i = 1; i < len - 1; ++i) {
+ squareDistance += pixelCalcDistance(ExtractCalcValue(func->Item(i)));
+ }
+ // Only iterate over elements 1 and 3. The <position> is 'uncomputed' to
+ // only those elements. See also the comment in SetPositionValue.
+ for (size_t i = 1; i < 4; i += 2) {
+ const nsCSSValue& value = func->Item(len - 1).GetArrayValue()->Item(i);
+ squareDistance += pixelCalcDistance(ExtractCalcValue(value));
+ }
+ break;
+ }
+ case eCSSKeyword_polygon:
+ // TODO: will be fixed in the later patch.
+ MOZ_ASSERT(false);
+ break;
+
+ case eCSSKeyword_inset:
+ // TODO: will be fixed in the later patch.
+ MOZ_ASSERT(false);
+ break;
+
+ default:
+ MOZ_ASSERT_UNREACHABLE("Unknown shape type");
+ }
+ return sqrt(squareDistance);
+}
+
static nsCSSValueList*
AddTransformLists(double aCoeff1, const nsCSSValueList* aList1,
double aCoeff2, const nsCSSValueList* aList2);
static double
ComputeTransform2DMatrixDistance(const Matrix& aMatrix1,
const Matrix& aMatrix2)
{
@@ -1423,19 +1490,20 @@ StyleAnimationValue::ComputeDistance(nsC
shadow1 = shadow1->mNext;
shadow2 = shadow2->mNext;
MOZ_ASSERT(!shadow1 == !shadow2, "lists should be same length");
}
aDistance = sqrt(squareDistance);
return true;
}
case eUnit_Shape:
- // Bug 1286150: The CSS Shapes spec doesn't define paced animations for
- // shape functions, but we still need to implement one.
- return false;
+ aDistance = ComputeShapeDistance(aProperty,
+ aStartValue.GetCSSValueArrayValue(),
+ aEndValue.GetCSSValueArrayValue());
+ return true;
case eUnit_Filter:
// Bug 1286151: Support paced animations for filter function
// interpolation.
return false;
case eUnit_Transform: {
// FIXME: We don't have an official spec to define the distance of
@@ -2145,26 +2213,21 @@ AddCSSValuePairList(nsCSSPropertyID aPro
if (aList1 || aList2) {
return nullptr; // We can't interpolate lists of different lengths
}
return result;
}
-enum class Restrictions {
- Enable,
- Disable
-};
-
static already_AddRefed<nsCSSValue::Array>
AddShapeFunction(nsCSSPropertyID aProperty,
double aCoeff1, const nsCSSValue::Array* aArray1,
double aCoeff2, const nsCSSValue::Array* aArray2,
- Restrictions aRestriction = Restrictions::Enable)
+ Restrictions aRestriction)
{
MOZ_ASSERT(aArray1 && aArray1->Count() == 2, "expected shape function");
MOZ_ASSERT(aArray2 && aArray2->Count() == 2, "expected shape function");
MOZ_ASSERT(aArray1->Item(0).GetUnit() == eCSSUnit_Function,
"expected function");
MOZ_ASSERT(aArray2->Item(0).GetUnit() == eCSSUnit_Function,
"expected function");
MOZ_ASSERT(aArray1->Item(1).GetUnit() == eCSSUnit_Enumerated,