Bug 1272549 - Part 9: Compute distance for mismatched transform lists.
MozReview-Commit-ID: JJWcMgj88GX
--- a/dom/animation/KeyframeEffectReadOnly.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -260,17 +260,17 @@ KeyframeEffectReadOnly::UpdateProperties
nsTArray<ComputedKeyframeValues> computedValues =
KeyframeUtils::GetComputedKeyframeValues(keyframesCopy,
mTarget->mElement,
aStyleContext);
if (mEffectOptions.mSpacingMode == SpacingMode::paced) {
KeyframeUtils::ApplySpacing(keyframesCopy, SpacingMode::paced,
mEffectOptions.mPacedProperty,
- computedValues);
+ computedValues, aStyleContext);
}
properties =
KeyframeUtils::GetAnimationPropertiesFromKeyframes(keyframesCopy,
computedValues,
aStyleContext);
#ifdef DEBUG
--- a/dom/animation/KeyframeUtils.cpp
+++ b/dom/animation/KeyframeUtils.cpp
@@ -411,17 +411,18 @@ static void
DistributeRange(const Range<Keyframe>& aSpacingRange);
static void
PaceRange(const Range<Keyframe>& aKeyframes,
const Range<double>& aCumulativeDistances);
static nsTArray<double>
GetCumulativeDistances(const nsTArray<ComputedKeyframeValues>& aValues,
- nsCSSPropertyID aProperty);
+ nsCSSPropertyID aProperty,
+ nsStyleContext* aStyleContext);
// ------------------------------------------------------------------
//
// Public API
//
// ------------------------------------------------------------------
/* static */ nsTArray<Keyframe>
@@ -475,28 +476,30 @@ KeyframeUtils::GetKeyframesFromObject(JS
return keyframes;
}
/* static */ void
KeyframeUtils::ApplySpacing(nsTArray<Keyframe>& aKeyframes,
SpacingMode aSpacingMode,
nsCSSPropertyID aProperty,
- nsTArray<ComputedKeyframeValues>& aComputedValues)
+ nsTArray<ComputedKeyframeValues>& aComputedValues,
+ nsStyleContext* aStyleContext)
{
if (aKeyframes.IsEmpty()) {
return;
}
nsTArray<double> cumulativeDistances;
if (aSpacingMode == SpacingMode::paced) {
MOZ_ASSERT(IsAnimatableProperty(aProperty),
"Paced property should be animatable");
- cumulativeDistances = GetCumulativeDistances(aComputedValues, aProperty);
+ cumulativeDistances = GetCumulativeDistances(aComputedValues, aProperty,
+ aStyleContext);
// Reset the computed offsets if using paced spacing.
for (Keyframe& keyframe : aKeyframes) {
keyframe.mComputedOffset = Keyframe::kComputedOffsetNotSet;
}
}
// If the first keyframe has an unspecified offset, fill it in with 0%.
// If there is only a single keyframe, then it gets 100%.
@@ -577,17 +580,17 @@ KeyframeUtils::ApplySpacing(nsTArray<Key
}
}
/* static */ void
KeyframeUtils::ApplyDistributeSpacing(nsTArray<Keyframe>& aKeyframes)
{
nsTArray<ComputedKeyframeValues> emptyArray;
ApplySpacing(aKeyframes, SpacingMode::distribute, eCSSProperty_UNKNOWN,
- emptyArray);
+ emptyArray, nullptr);
}
/* static */ nsTArray<ComputedKeyframeValues>
KeyframeUtils::GetComputedKeyframeValues(const nsTArray<Keyframe>& aKeyframes,
dom::Element* aElement,
nsStyleContext* aStyleContext)
{
MOZ_ASSERT(aStyleContext);
@@ -1558,22 +1561,24 @@ PaceRange(const Range<Keyframe>& aKeyfra
}
}
/**
* Get cumulative distances for the paced property.
*
* @param aValues The computed values returned by GetComputedKeyframeValues.
* @param aPacedProperty The paced property.
+ * @param aStyleContext The style context for computing distance on transform.
* @return The cumulative distances for the paced property. The length will be
* the same as aValues.
*/
static nsTArray<double>
GetCumulativeDistances(const nsTArray<ComputedKeyframeValues>& aValues,
- nsCSSPropertyID aPacedProperty)
+ nsCSSPropertyID aPacedProperty,
+ nsStyleContext* aStyleContext)
{
// a) If aPacedProperty is a shorthand property, get its components.
// Otherwise, just add the longhand property into the set.
size_t pacedPropertyCount = 0;
nsCSSPropertyIDSet pacedPropertySet;
bool isShorthand = nsCSSProps::IsShorthand(aPacedProperty);
if (isShorthand) {
CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(p, aPacedProperty,
@@ -1631,29 +1636,31 @@ GetCumulativeDistances(const nsTArray<Co
MOZ_ASSERT(pacedValues[propIdx].mProperty == prop,
"Property mismatch");
double componentDistance = 0.0;
if (StyleAnimationValue::ComputeDistance(
prop,
prevPacedValues[propIdx].mValue,
pacedValues[propIdx].mValue,
+ aStyleContext,
componentDistance)) {
dist += componentDistance * componentDistance;
}
}
dist = sqrt(dist);
} else {
// If the property is longhand, we just use the 1st value.
// If ComputeDistance() fails, |dist| will remain zero so there will be
// no distance between the previous paced value and this value.
Unused <<
StyleAnimationValue::ComputeDistance(aPacedProperty,
prevPacedValues[0].mValue,
pacedValues[0].mValue,
+ aStyleContext,
dist);
}
cumulativeDistances[i] = cumulativeDistances[preIdx] + dist;
}
prevPacedValues.SwapElements(pacedValues);
preIdx = i;
}
return cumulativeDistances;
--- a/dom/animation/KeyframeUtils.h
+++ b/dom/animation/KeyframeUtils.h
@@ -93,21 +93,24 @@ public:
* @param aSpacingMode The spacing mode to apply.
* @param aProperty The paced property. Only used when |aSpacingMode| is
* SpacingMode::paced. In all other cases it is ignored and hence may be
* any value, e.g. eCSSProperty_UNKNOWN.
* @param aComputedValues The set of computed keyframe values as returned by
* GetComputedKeyframeValues. Only used when |aSpacingMode| is
* SpacingMode::paced. In all other cases this parameter is unused and may
* be any value including an empty array.
+ * @param aStyleContext The style context used for calculating paced spacing
+ * on transform.
*/
static void ApplySpacing(nsTArray<Keyframe>& aKeyframes,
SpacingMode aSpacingMode,
nsCSSPropertyID aProperty,
- nsTArray<ComputedKeyframeValues>& aComputedValues);
+ nsTArray<ComputedKeyframeValues>& aComputedValues,
+ nsStyleContext* aStyleContext);
/**
* Wrapper for ApplySpacing to simplify using distribute spacing.
*
* @param aKeyframes The set of keyframes to adjust.
*/
static void ApplyDistributeSpacing(nsTArray<Keyframe>& aKeyframes);
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2698,23 +2698,29 @@ nsDOMWindowUtils::ComputeAnimationDistan
property = eCSSProperty_UNKNOWN;
}
MOZ_ASSERT(property == eCSSProperty_UNKNOWN ||
!nsCSSProps::IsShorthand(property),
"should not have shorthand");
StyleAnimationValue v1, v2;
+ Element* element = content->AsElement();
if (property == eCSSProperty_UNKNOWN ||
- !ComputeAnimationValue(property, content->AsElement(), aValue1, v1) ||
- !ComputeAnimationValue(property, content->AsElement(), aValue2, v2)) {
+ !ComputeAnimationValue(property, element, aValue1, v1) ||
+ !ComputeAnimationValue(property, element, aValue2, v2)) {
return NS_ERROR_ILLEGAL_VALUE;
}
- if (!StyleAnimationValue::ComputeDistance(property, v1, v2, *aResult)) {
+ nsIPresShell* shell = element->GetUncomposedDoc()->GetShell();
+ RefPtr<nsStyleContext> styleContext = shell
+ ? nsComputedDOMStyle::GetStyleContextForElement(element, nullptr, shell)
+ : nullptr;
+ if (!StyleAnimationValue::ComputeDistance(property, v1, v2, styleContext,
+ *aResult)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
nsDOMWindowUtils::RenderDocument(const nsRect& aRect,
--- a/dom/smil/nsSMILCSSValueType.cpp
+++ b/dom/smil/nsSMILCSSValueType.cpp
@@ -273,16 +273,17 @@ nsSMILCSSValueType::ComputeDistance(cons
&fromWrapper->mCSSValue : nullptr;
const StyleAnimationValue* toCSSValue = &toWrapper->mCSSValue;
if (!FinalizeStyleAnimationValues(fromCSSValue, toCSSValue)) {
return NS_ERROR_FAILURE;
}
return StyleAnimationValue::ComputeDistance(toWrapper->mPropID,
*fromCSSValue, *toCSSValue,
+ nullptr,
aDistance) ?
NS_OK : NS_ERROR_FAILURE;
}
nsresult
nsSMILCSSValueType::Interpolate(const nsSMILValue& aStartVal,
const nsSMILValue& aEndVal,
double aUnitDistance,
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -1010,20 +1010,55 @@ ComputeTransformListDistance(const nsCSS
aList1 = aList1->mNext;
aList2 = aList2->mNext;
MOZ_ASSERT(!aList1 == !aList2,
"aList1 and aList2 should have the same length.");
} while (aList1);
return sqrt(distance);
}
+static double
+ComputeMismatchedTransfromListDistance(const nsCSSValueList* aList1,
+ const nsCSSValueList* aList2,
+ nsStyleContext* aStyleContext)
+{
+ // We need nsStyleContext and nsPresContext to compute calc() values while
+ // processing the translate part of transforms.
+ if (!aStyleContext) {
+ return 0.0;
+ }
+
+ RuleNodeCacheConditions dontCare;
+ bool dontCareBool;
+ nsStyleTransformMatrix::TransformReferenceBox emptyRefBox;
+
+ Matrix4x4 m1 = nsStyleTransformMatrix::ReadTransforms(
+ aList1,
+ aStyleContext,
+ aStyleContext->PresContext(),
+ dontCare,
+ emptyRefBox,
+ nsPresContext::AppUnitsPerCSSPixel(),
+ &dontCareBool);
+ Matrix4x4 m2 = nsStyleTransformMatrix::ReadTransforms(
+ aList2,
+ aStyleContext,
+ aStyleContext->PresContext(),
+ dontCare,
+ emptyRefBox,
+ nsPresContext::AppUnitsPerCSSPixel(),
+ &dontCareBool);
+ return sqrt(ComputeTransform3DMatrixDistance(m1, m2));
+}
+
bool
StyleAnimationValue::ComputeDistance(nsCSSPropertyID aProperty,
const StyleAnimationValue& aStartValue,
const StyleAnimationValue& aEndValue,
+ nsStyleContext* aStyleContext,
double& aDistance)
{
Unit commonUnit =
GetCommonUnit(aProperty, aStartValue.GetUnit(), aEndValue.GetUnit());
switch (commonUnit) {
case eUnit_Null:
case eUnit_Auto:
@@ -1427,23 +1462,21 @@ StyleAnimationValue::ComputeDistance(nsC
item1 = item1->mNext;
item2 = item2->mNext;
} while (item1 && item2);
if (item1 || item2) {
// Either the transform function types don't match or
// the lengths don't match.
-
- // TODO: Implement this for mismatched transform function in the later
- // patch.
- aDistance = 0.0;
- return false;
+ aDistance =
+ ComputeMismatchedTransfromListDistance(list1, list2, aStyleContext);
+ } else {
+ aDistance = ComputeTransformListDistance(list1, list2);
}
- aDistance = ComputeTransformListDistance(list1, list2);
}
return true;
}
case eUnit_BackgroundPositionCoord: {
const nsCSSValueList *position1 = aStartValue.GetCSSValueListValue();
const nsCSSValueList *position2 = aEndValue.GetCSSValueListValue();
double squareDistance = 0.0;
--- a/layout/style/StyleAnimationValue.h
+++ b/layout/style/StyleAnimationValue.h
@@ -82,23 +82,26 @@ public:
*
* If this method succeeds, the returned distance value is guaranteed to be
* non-negative.
*
* @param aStartValue The start of the interval for which the distance
* should be calculated.
* @param aEndValue The end of the interval for which the distance
* should be calculated.
+ * @param aStyleContext The style context to use for processing the
+ * translate part of transforms.
* @param aDistance The result of the calculation.
* @return true on success, false on failure.
*/
static MOZ_MUST_USE bool
ComputeDistance(nsCSSPropertyID aProperty,
const StyleAnimationValue& aStartValue,
const StyleAnimationValue& aEndValue,
+ nsStyleContext* aStyleContext,
double& aDistance);
/**
* Calculates an interpolated value that is the specified |aPortion| between
* the two given values.
*
* This really just does the following calculation:
* aResultValue = (1.0 - aPortion) * aStartValue + aPortion * aEndValue
--- a/layout/style/nsStyleTransformMatrix.cpp
+++ b/layout/style/nsStyleTransformMatrix.cpp
@@ -172,17 +172,17 @@ ProcessTranslatePart(const nsCSSValue& a
offset = nsRuleNode::CalcLength(aValue, aContext, aPresContext,
aConditions);
}
float translation = NSAppUnitsToFloatPixels(offset,
nsPresContext::AppUnitsPerCSSPixel());
// We want to avoid calling aDimensionGetter if there's no percentage to be
// resolved (for performance reasons - see TransformReferenceBox).
- if (percent != 0.0f && aRefBox) {
+ if (percent != 0.0f && aRefBox && !aRefBox->IsEmpty()) {
translation += percent *
NSAppUnitsToFloatPixels((aRefBox->*aDimensionGetter)(),
nsPresContext::AppUnitsPerCSSPixel());
}
return translation;
}
/**
--- a/layout/style/nsStyleTransformMatrix.h
+++ b/layout/style/nsStyleTransformMatrix.h
@@ -105,16 +105,20 @@ namespace nsStyleTransformMatrix {
EnsureDimensionsAreCached();
return mWidth;
}
nscoord Height() {
EnsureDimensionsAreCached();
return mHeight;
}
+ bool IsEmpty() {
+ return !mFrame;
+ }
+
private:
// We don't really need to prevent copying, but since none of our consumers
// currently need to copy, preventing copying may allow us to catch some
// cases where we use pass-by-value instead of pass-by-reference.
TransformReferenceBox(const TransformReferenceBox&) = delete;
void EnsureDimensionsAreCached();