Bug 1055285 part 3: Implement animation for 'object-position' property. r=heycam

This commit is contained in:
Daniel Holbert 2014-09-09 18:09:32 -07:00
parent c6d3b18b7d
commit 74d038dd95
4 changed files with 114 additions and 46 deletions

View File

@ -558,6 +558,15 @@ StyleAnimationValue::ComputeDistance(nsCSSProperty aProperty,
aDistance = sqrt(difflen * difflen + diffpct * diffpct);
return true;
}
case eUnit_ObjectPosition: {
const nsCSSValue* position1 = aStartValue.GetCSSValueValue();
const nsCSSValue* position2 = aEndValue.GetCSSValueValue();
double squareDistance =
CalcPositionSquareDistance(*position1,
*position2);
aDistance = sqrt(squareDistance);
return true;
}
case eUnit_CSSValuePair: {
const nsCSSValuePair *pair1 = aStartValue.GetCSSValuePairValue();
const nsCSSValuePair *pair2 = aEndValue.GetCSSValuePairValue();
@ -2067,6 +2076,18 @@ StyleAnimationValue::AddWeighted(nsCSSProperty aProperty,
aResultValue.SetAndAdoptCSSValueValue(val, eUnit_Calc);
return true;
}
case eUnit_ObjectPosition: {
const nsCSSValue* position1 = aValue1.GetCSSValueValue();
const nsCSSValue* position2 = aValue2.GetCSSValueValue();
nsAutoPtr<nsCSSValue> result(new nsCSSValue);
AddPositions(aCoeff1, *position1,
aCoeff2, *position2, *result);
aResultValue.SetAndAdoptCSSValueValue(result.forget(),
eUnit_ObjectPosition);
return true;
}
case eUnit_CSSValuePair: {
const nsCSSValuePair *pair1 = aValue1.GetCSSValuePairValue();
const nsCSSValuePair *pair2 = aValue2.GetCSSValuePairValue();
@ -2609,7 +2630,8 @@ StyleAnimationValue::UncomputeValue(nsCSSProperty aProperty,
const StyleAnimationValue& aComputedValue,
nsCSSValue& aSpecifiedValue)
{
switch (aComputedValue.GetUnit()) {
Unit unit = aComputedValue.GetUnit();
switch (unit) {
case eUnit_Normal:
aSpecifiedValue.SetNormalValue();
break;
@ -2642,9 +2664,15 @@ StyleAnimationValue::UncomputeValue(nsCSSProperty aProperty,
// colors can be alone, or part of a paint server
aSpecifiedValue.SetColorValue(aComputedValue.GetColorValue());
break;
case eUnit_Calc: {
nsCSSValue *val = aComputedValue.GetCSSValueValue();
NS_ABORT_IF_FALSE(val->GetUnit() == eCSSUnit_Calc, "unexpected unit");
case eUnit_Calc:
case eUnit_ObjectPosition: {
nsCSSValue* val = aComputedValue.GetCSSValueValue();
// Sanity-check that the underlying unit in the nsCSSValue is what we
// expect for our StyleAnimationValue::Unit:
MOZ_ASSERT((unit == eUnit_Calc && val->GetUnit() == eCSSUnit_Calc) ||
(unit == eUnit_ObjectPosition &&
val->GetUnit() == eCSSUnit_Array),
"unexpected unit");
aSpecifiedValue = *val;
break;
}
@ -3180,6 +3208,18 @@ StyleAnimationValue::ExtractComputedValue(nsCSSProperty aProperty,
break;
}
case eCSSProperty_object_position: {
const nsStylePosition* stylePos =
static_cast<const nsStylePosition*>(styleStruct);
nsAutoPtr<nsCSSValue> val(new nsCSSValue);
SetPositionValue(stylePos->mObjectPosition, *val);
aComputedValue.SetAndAdoptCSSValueValue(val.forget(),
eUnit_ObjectPosition);
break;
}
case eCSSProperty_background_position: {
const nsStyleBackground *bg =
static_cast<const nsStyleBackground*>(styleStruct);
@ -3574,6 +3614,9 @@ StyleAnimationValue::operator=(const StyleAnimationValue& aOther)
mValue.mColor = aOther.mValue.mColor;
break;
case eUnit_Calc:
case eUnit_ObjectPosition:
NS_ABORT_IF_FALSE(IsCSSValueUnit(mUnit),
"This clause is for handling nsCSSValue-backed units");
NS_ABORT_IF_FALSE(aOther.mValue.mCSSValue, "values may not be null");
mValue.mCSSValue = new nsCSSValue(*aOther.mValue.mCSSValue);
if (!mValue.mCSSValue) {
@ -3836,6 +3879,9 @@ StyleAnimationValue::operator==(const StyleAnimationValue& aOther) const
case eUnit_Color:
return mValue.mColor == aOther.mValue.mColor;
case eUnit_Calc:
case eUnit_ObjectPosition:
NS_ABORT_IF_FALSE(IsCSSValueUnit(mUnit),
"This clause is for handling nsCSSValue-backed units");
return *mValue.mCSSValue == *aOther.mValue.mCSSValue;
case eUnit_CSSValuePair:
return *mValue.mCSSValuePair == *aOther.mValue.mCSSValuePair;

View File

@ -214,6 +214,8 @@ public:
eUnit_Color,
eUnit_Calc, // nsCSSValue* (never null), always with a single
// calc() expression that's either length or length+percent
eUnit_ObjectPosition, // nsCSSValue* (never null), always with a
// 4-entry nsCSSValue::Array
eUnit_CSSValuePair, // nsCSSValuePair* (never null)
eUnit_CSSValueTriplet, // nsCSSValueTriplet* (never null)
eUnit_CSSRect, // nsCSSRect* (never null)
@ -374,7 +376,8 @@ private:
aUnit == eUnit_Integer;
}
static bool IsCSSValueUnit(Unit aUnit) {
return aUnit == eUnit_Calc;
return aUnit == eUnit_Calc ||
aUnit == eUnit_ObjectPosition;
}
static bool IsCSSValuePairUnit(Unit aUnit) {
return aUnit == eUnit_CSSValuePair;

View File

@ -2540,8 +2540,8 @@ CSS_PROP_POSITION(
"layout.css.object-fit-and-position.enabled",
0,
kBackgroundPositionKTable,
CSS_PROP_NO_OFFSET,
eStyleAnimType_None) // XXXdholbert Use "_Custom", and implement animation
offsetof(nsStylePosition, mObjectPosition),
eStyleAnimType_Custom)
CSS_PROP_DISPLAY(
opacity,
opacity,

View File

@ -182,6 +182,7 @@ var supported_properties = {
"min-width": [ test_length_transition, test_percent_transition,
test_length_percent_calc_transition,
test_length_clamped, test_percent_clamped ],
"object-position": [ test_background_position_transition ],
"opacity" : [ test_float_zeroToOne_transition,
// opacity is clamped in computed style
// (not parsing/interpolation)
@ -1813,7 +1814,7 @@ function test_background_size_transition(prop) {
div.style.setProperty(prop, "contain", "");
is(cs.getPropertyValue(prop), "contain",
"property " + prop + ": can't interpolate 'contain'");
test_background_position_size_common(prop);
test_background_position_size_common(prop, true);
}
function test_background_position_transition(prop) {
@ -1826,10 +1827,24 @@ function test_background_position_transition(prop) {
is(cs.getPropertyValue(prop), "62.5% 85%",
"property " + prop + ": interpolation of percents");
check_distance(prop, "center 80%", "62.5% 85%", "bottom right");
test_background_position_size_common(prop);
var doesPropTakeListValues = (prop == "background-position");
test_background_position_size_common(prop, doesPropTakeListValues);
}
function test_background_position_size_common(prop) {
/**
* Common tests for 'background-position', 'background-size', and other
* properties that take CSS value-type 'position' or 'bg-size'.
*
* @arg prop The name of the property
* @arg doesPropTakeListValues
* If false, the property is assumed to just take a single 'position' or
* 'bg-size' value. If true, the property is assumed to also accept
* comma-separated list of such values.
*/
function test_background_position_size_common(prop, doesPropTakeListValues) {
// Test non-list values
div.style.setProperty("transition-property", "none", "");
div.style.setProperty(prop, "40% 0%", "");
is(cs.getPropertyValue(prop), "40% 0%",
@ -1859,42 +1874,46 @@ function test_background_position_size_common(prop) {
is(cs.getPropertyValue(prop), "20px 30px",
"property " + prop + ": interpolation of lengths");
check_distance(prop, "10px 40px", "20px 30px", "50px 0");
div.style.setProperty(prop, "10px 40px, 50px 50px, 30px 20px", "");
is(cs.getPropertyValue(prop), "10px 40px, 50px 50px, 30px 20px",
"property " + prop + ": computed value before transition");
div.style.setProperty(prop, "50px 20px, 70px 50px, 30px 40px", "");
is(cs.getPropertyValue(prop), "20px 35px, 55px 50px, 30px 25px",
"property " + prop + ": interpolation of lists of lengths");
check_distance(prop, "10px 40px, 50px 50px, 30px 20px",
"20px 35px, 55px 50px, 30px 25px",
"50px 20px, 70px 50px, 30px 40px");
div.style.setProperty(prop, "10px 40%, 50% 50px, 30% 20%, 5px 10px", "");
is(cs.getPropertyValue(prop), "10px 40%, 50% 50px, 30% 20%, 5px 10px",
"property " + prop + ": computed value before transition");
div.style.setProperty(prop, "50px 20%, 70% 50px, 30% 40%, 25px 50px", "");
is(cs.getPropertyValue(prop), "20px 35%, 55% 50px, 30% 25%, 10px 20px",
"property " + prop + ": interpolation of lists of lengths and percents");
check_distance(prop, "10px 40%, 50% 50px, 30% 20%, 5px 10px",
"20px 35%, 55% 50px, 30% 25%, 10px 20px",
"50px 20%, 70% 50px, 30% 40%, 25px 50px");
div.style.setProperty(prop, "20% 40%, 8px 12px", "");
is(cs.getPropertyValue(prop), "20% 40%, 8px 12px",
"property " + prop + ": computed value before transition");
div.style.setProperty(prop, "12px 20px, 40% 16%", "");
is(cs.getPropertyValue(prop), "calc(3px + 15%) calc(5px + 30%), calc(6px + 10%) calc(9px + 4%)",
"property " + prop + ": interpolation that computes to calc()");
check_distance(prop, "20% 40%, 8px 12px",
"calc(3px + 15%) calc(5px + 30%), calc(6px + 10%) calc(9px + 4%)",
"12px 20px, 40% 16%");
div.style.setProperty(prop, "calc(20% + 40px) calc(40px + 40%), 8px 12%, calc(20px + 12%) calc(24px + 8%)", "");
is(cs.getPropertyValue(prop), "calc(40px + 20%) calc(40px + 40%), 8px 12%, calc(20px + 12%) calc(24px + 8%)",
"property " + prop + ": computed value before transition");
div.style.setProperty(prop, "12px 20%, calc(20%) calc(16px + 60%), calc(8px + 20%) calc(40px + 16%)", "");
is(cs.getPropertyValue(prop), "calc(33px + 15%) calc(30px + 35%), calc(6px + 5%) calc(4px + 24%), calc(17px + 14%) calc(28px + 10%)",
"property " + prop + ": interpolation that computes to calc()");
check_distance(prop, "calc(20% + 40px) calc(40px + 40%), 8px 12%, calc(20px + 12%) calc(24px + 8%)",
"calc(33px + 15%) calc(30px + 35%), calc(6px + 5%) calc(4px + 24%), calc(17px + 14%) calc(28px + 10%)",
"12px 20%, calc(20%) calc(16px + 60%), calc(8px + 20%) calc(40px + 16%)");
// Test list values, if appropriate
if (doesPropTakeListValues) {
div.style.setProperty(prop, "10px 40px, 50px 50px, 30px 20px", "");
is(cs.getPropertyValue(prop), "10px 40px, 50px 50px, 30px 20px",
"property " + prop + ": computed value before transition");
div.style.setProperty(prop, "50px 20px, 70px 50px, 30px 40px", "");
is(cs.getPropertyValue(prop), "20px 35px, 55px 50px, 30px 25px",
"property " + prop + ": interpolation of lists of lengths");
check_distance(prop, "10px 40px, 50px 50px, 30px 20px",
"20px 35px, 55px 50px, 30px 25px",
"50px 20px, 70px 50px, 30px 40px");
div.style.setProperty(prop, "10px 40%, 50% 50px, 30% 20%, 5px 10px", "");
is(cs.getPropertyValue(prop), "10px 40%, 50% 50px, 30% 20%, 5px 10px",
"property " + prop + ": computed value before transition");
div.style.setProperty(prop, "50px 20%, 70% 50px, 30% 40%, 25px 50px", "");
is(cs.getPropertyValue(prop), "20px 35%, 55% 50px, 30% 25%, 10px 20px",
"property " + prop + ": interpolation of lists of lengths and percents");
check_distance(prop, "10px 40%, 50% 50px, 30% 20%, 5px 10px",
"20px 35%, 55% 50px, 30% 25%, 10px 20px",
"50px 20%, 70% 50px, 30% 40%, 25px 50px");
div.style.setProperty(prop, "20% 40%, 8px 12px", "");
is(cs.getPropertyValue(prop), "20% 40%, 8px 12px",
"property " + prop + ": computed value before transition");
div.style.setProperty(prop, "12px 20px, 40% 16%", "");
is(cs.getPropertyValue(prop), "calc(3px + 15%) calc(5px + 30%), calc(6px + 10%) calc(9px + 4%)",
"property " + prop + ": interpolation that computes to calc()");
check_distance(prop, "20% 40%, 8px 12px",
"calc(3px + 15%) calc(5px + 30%), calc(6px + 10%) calc(9px + 4%)",
"12px 20px, 40% 16%");
div.style.setProperty(prop, "calc(20% + 40px) calc(40px + 40%), 8px 12%, calc(20px + 12%) calc(24px + 8%)", "");
is(cs.getPropertyValue(prop), "calc(40px + 20%) calc(40px + 40%), 8px 12%, calc(20px + 12%) calc(24px + 8%)",
"property " + prop + ": computed value before transition");
div.style.setProperty(prop, "12px 20%, calc(20%) calc(16px + 60%), calc(8px + 20%) calc(40px + 16%)", "");
is(cs.getPropertyValue(prop), "calc(33px + 15%) calc(30px + 35%), calc(6px + 5%) calc(4px + 24%), calc(17px + 14%) calc(28px + 10%)",
"property " + prop + ": interpolation that computes to calc()");
check_distance(prop, "calc(20% + 40px) calc(40px + 40%), 8px 12%, calc(20px + 12%) calc(24px + 8%)",
"calc(33px + 15%) calc(30px + 35%), calc(6px + 5%) calc(4px + 24%), calc(17px + 14%) calc(28px + 10%)",
"12px 20%, calc(20%) calc(16px + 60%), calc(8px + 20%) calc(40px + 16%)");
}
}
function test_transform_transition(prop) {