Add support for animation of nsRect values. (Bug 520488) r=bzbarsky

This commit is contained in:
L. David Baron 2009-12-21 16:46:25 -05:00
parent 544fa1d874
commit 4cb8a38d3f
5 changed files with 218 additions and 38 deletions

View File

@ -1190,8 +1190,8 @@ CSS_PROP_DISPLAY(
mClip,
eCSSType_Rect,
nsnull,
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
offsetof(nsStyleDisplay, mClip),
eStyleAnimType_Custom)
CSS_PROP_COLOR(
color,
color,
@ -1523,8 +1523,8 @@ CSS_PROP_LIST(
mImageRegion,
eCSSType_Rect,
nsnull,
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
offsetof(nsStyleList, mImageRegion),
eStyleAnimType_Custom)
CSS_PROP_UIRESET(
ime-mode,
ime_mode,

View File

@ -244,6 +244,42 @@ nsStyleAnimation::ComputeDistance(nsCSSProperty aProperty,
aDistance = sqrt(squareDistance);
break;
}
case eUnit_CSSRect: {
const nsCSSRect *rect1 = aStartValue.GetCSSRectValue();
const nsCSSRect *rect2 = aEndValue.GetCSSRectValue();
if (rect1->mTop.GetUnit() != rect2->mTop.GetUnit() ||
rect1->mRight.GetUnit() != rect2->mRight.GetUnit() ||
rect1->mBottom.GetUnit() != rect2->mBottom.GetUnit() ||
rect1->mLeft.GetUnit() != rect2->mLeft.GetUnit()) {
// At least until we have calc()
return PR_FALSE;
}
double squareDistance = 0.0;
for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(nsCSSRect::sides); ++i) {
nsCSSValue nsCSSRect::*member = nsCSSRect::sides[i];
NS_ABORT_IF_FALSE((rect1->*member).GetUnit() ==
(rect2->*member).GetUnit(),
"should have returned above");
double diff;
switch ((rect1->*member).GetUnit()) {
case eCSSUnit_Pixel:
diff = (rect1->*member).GetFloatValue() -
(rect2->*member).GetFloatValue();
break;
case eCSSUnit_Auto:
diff = 0;
break;
default:
NS_ABORT_IF_FALSE(PR_FALSE, "unexpected unit");
return PR_FALSE;
}
squareDistance += diff * diff;
}
aDistance = sqrt(squareDistance);
break;
}
case eUnit_Dasharray: {
// NOTE: This produces results on substantially different scales
// for length values and percentage values, which might even be
@ -366,6 +402,13 @@ nsStyleAnimation::ComputeDistance(nsCSSProperty aProperty,
return success;
}
inline void
nscoordToCSSValue(nscoord aCoord, nsCSSValue& aCSSValue)
{
aCSSValue.SetFloatValue(nsPresContext::AppUnitsToFloatCSSPixels(aCoord),
eCSSUnit_Pixel);
}
#define MAX_PACKED_COLOR_COMPONENT 255
inline PRUint8 ClampColor(double aColor)
@ -586,6 +629,50 @@ nsStyleAnimation::AddWeighted(nsCSSProperty aProperty,
eUnit_CSSValuePair);
break;
}
case eUnit_CSSRect: {
const nsCSSRect *rect1 = aValue1.GetCSSRectValue();
const nsCSSRect *rect2 = aValue2.GetCSSRectValue();
if (rect1->mTop.GetUnit() != rect2->mTop.GetUnit() ||
rect1->mRight.GetUnit() != rect2->mRight.GetUnit() ||
rect1->mBottom.GetUnit() != rect2->mBottom.GetUnit() ||
rect1->mLeft.GetUnit() != rect2->mLeft.GetUnit()) {
// At least until we have calc()
return PR_FALSE;
}
nsAutoPtr<nsCSSRect> result(new nsCSSRect);
if (!result) {
return PR_FALSE;
}
for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(nsCSSRect::sides); ++i) {
nsCSSValue nsCSSRect::*member = nsCSSRect::sides[i];
NS_ABORT_IF_FALSE((rect1->*member).GetUnit() ==
(rect2->*member).GetUnit(),
"should have returned above");
switch ((rect1->*member).GetUnit()) {
case eCSSUnit_Pixel:
(result->*member).SetFloatValue(
aCoeff1 * (rect1->*member).GetFloatValue() +
aCoeff2 * (rect2->*member).GetFloatValue(),
eCSSUnit_Pixel);
break;
case eCSSUnit_Auto:
if (float(aCoeff1 + aCoeff2) != 1.0f) {
// Interpolating between two auto values makes sense;
// adding in other ratios does not.
return PR_FALSE;
}
(result->*member).SetAutoValue();
break;
default:
NS_ABORT_IF_FALSE(PR_FALSE, "unexpected unit");
return PR_FALSE;
}
}
aResultValue.SetAndAdoptCSSRectValue(result.forget(), eUnit_CSSRect);
break;
}
case eUnit_Dasharray: {
const nsCSSValueList *list1 = aValue1.GetCSSValueListValue();
const nsCSSValueList *list2 = aValue2.GetCSSValueListValue();
@ -896,10 +983,8 @@ nsStyleAnimation::UncomputeValue(nsCSSProperty aProperty,
case eUnit_Coord: {
NS_ABORT_IF_FALSE(nsCSSProps::kTypeTable[aProperty] == eCSSType_Value,
"type mismatch");
float pxVal = aPresContext->AppUnitsToFloatCSSPixels(
aComputedValue.GetCoordValue());
static_cast<nsCSSValue*>(aSpecifiedValue)->
SetFloatValue(pxVal, eCSSUnit_Pixel);
nscoordToCSSValue(aComputedValue.GetCoordValue(),
*static_cast<nsCSSValue*>(aSpecifiedValue));
break;
}
case eUnit_Percent:
@ -936,6 +1021,12 @@ nsStyleAnimation::UncomputeValue(nsCSSProperty aProperty,
*static_cast<nsCSSValuePair*>(aSpecifiedValue) =
*aComputedValue.GetCSSValuePairValue();
break;
case eUnit_CSSRect:
NS_ABORT_IF_FALSE(nsCSSProps::kTypeTable[aProperty] ==
eCSSType_Rect, "type mismatch");
*static_cast<nsCSSRect*>(aSpecifiedValue) =
*aComputedValue.GetCSSRectValue();
break;
case eUnit_Dasharray:
case eUnit_Shadow:
NS_ABORT_IF_FALSE(nsCSSProps::kTypeTable[aProperty] ==
@ -1063,9 +1154,7 @@ StyleCoordToCSSValue(const nsStyleCoord& aCoord, nsCSSValue& aCSSValue)
{
switch (aCoord.GetUnit()) {
case eStyleUnit_Coord:
aCSSValue.SetFloatValue(nsPresContext::AppUnitsToFloatCSSPixels(
aCoord.GetCoordValue()),
eCSSUnit_Pixel);
nscoordToCSSValue(aCoord.GetCoordValue(), aCSSValue);
break;
case eStyleUnit_Percent:
aCSSValue.SetPercentValue(aCoord.GetPercentValue());
@ -1164,14 +1253,8 @@ nsStyleAnimation::ExtractComputedValue(nsCSSProperty aProperty,
if (!pair) {
return PR_FALSE;
}
pair->mXValue.SetFloatValue(
nsPresContext::AppUnitsToFloatCSSPixels(
styleTableBorder->mBorderSpacingX),
eCSSUnit_Pixel);
pair->mYValue.SetFloatValue(
nsPresContext::AppUnitsToFloatCSSPixels(
styleTableBorder->mBorderSpacingY),
eCSSUnit_Pixel);
nscoordToCSSValue(styleTableBorder->mBorderSpacingX, pair->mXValue);
nscoordToCSSValue(styleTableBorder->mBorderSpacingY, pair->mYValue);
aComputedValue.SetAndAdoptCSSValuePairValue(pair,
eUnit_CSSValuePair);
break;
@ -1270,6 +1353,64 @@ nsStyleAnimation::ExtractComputedValue(nsCSSProperty aProperty,
return PR_TRUE;
}
case eCSSProperty_image_region: {
const nsStyleList *list =
static_cast<const nsStyleList*>(styleStruct);
const nsRect &srect = list->mImageRegion;
if (srect.IsEmpty()) {
aComputedValue.SetAutoValue();
break;
}
nsCSSRect *vrect = new nsCSSRect;
if (!vrect) {
return PR_FALSE;
}
nscoordToCSSValue(srect.x, vrect->mLeft);
nscoordToCSSValue(srect.y, vrect->mTop);
nscoordToCSSValue(srect.XMost(), vrect->mRight);
nscoordToCSSValue(srect.YMost(), vrect->mBottom);
aComputedValue.SetAndAdoptCSSRectValue(vrect, eUnit_CSSRect);
break;
}
case eCSSProperty_clip: {
const nsStyleDisplay *display =
static_cast<const nsStyleDisplay*>(styleStruct);
if (!(display->mClipFlags & NS_STYLE_CLIP_RECT)) {
aComputedValue.SetAutoValue();
break;
}
nsCSSRect *vrect = new nsCSSRect;
if (!vrect) {
return PR_FALSE;
}
const nsRect &srect = display->mClip;
if (display->mClipFlags & NS_STYLE_CLIP_TOP_AUTO) {
vrect->mTop.SetAutoValue();
} else {
nscoordToCSSValue(srect.y, vrect->mTop);
}
if (display->mClipFlags & NS_STYLE_CLIP_RIGHT_AUTO) {
vrect->mRight.SetAutoValue();
} else {
nscoordToCSSValue(srect.XMost(), vrect->mRight);
}
if (display->mClipFlags & NS_STYLE_CLIP_BOTTOM_AUTO) {
vrect->mBottom.SetAutoValue();
} else {
nscoordToCSSValue(srect.YMost(), vrect->mBottom);
}
if (display->mClipFlags & NS_STYLE_CLIP_LEFT_AUTO) {
vrect->mLeft.SetAutoValue();
} else {
nscoordToCSSValue(srect.x, vrect->mLeft);
}
aComputedValue.SetAndAdoptCSSRectValue(vrect, eUnit_CSSRect);
break;
}
default:
NS_ABORT_IF_FALSE(PR_FALSE, "missing property implementation");
return PR_FALSE;
@ -1376,20 +1517,12 @@ nsStyleAnimation::ExtractComputedValue(nsCSSProperty aProperty,
const nsCSSShadowItem *shadow = shadowArray->ShadowAt(i);
// X, Y, Radius, Spread, Color, Inset
nsRefPtr<nsCSSValue::Array> arr = nsCSSValue::Array::Create(6);
arr->Item(0).SetFloatValue(
nsPresContext::AppUnitsToFloatCSSPixels(shadow->mXOffset),
eCSSUnit_Pixel);
arr->Item(1).SetFloatValue(
nsPresContext::AppUnitsToFloatCSSPixels(shadow->mYOffset),
eCSSUnit_Pixel);
arr->Item(2).SetFloatValue(
nsPresContext::AppUnitsToFloatCSSPixels(shadow->mRadius),
eCSSUnit_Pixel);
nscoordToCSSValue(shadow->mXOffset, arr->Item(0));
nscoordToCSSValue(shadow->mYOffset, arr->Item(1));
nscoordToCSSValue(shadow->mRadius, arr->Item(2));
// NOTE: This code sometimes stores mSpread: 0 even when
// the parser would be required to leave it null.
arr->Item(3).SetFloatValue(
nsPresContext::AppUnitsToFloatCSSPixels(shadow->mSpread),
eCSSUnit_Pixel);
nscoordToCSSValue(shadow->mSpread, arr->Item(3));
if (shadow->mHasColor) {
arr->Item(4).SetColorValue(shadow->mColor);
}
@ -1482,6 +1615,13 @@ nsStyleAnimation::Value::operator=(const Value& aOther)
mUnit = eUnit_Null;
}
break;
case eUnit_CSSRect:
NS_ABORT_IF_FALSE(aOther.mValue.mCSSRect, "rects may not be null");
mValue.mCSSRect = new nsCSSRect(*aOther.mValue.mCSSRect);
if (!mValue.mCSSRect) {
mUnit = eUnit_Null;
}
break;
case eUnit_Dasharray:
case eUnit_Shadow:
NS_ABORT_IF_FALSE(mUnit != eUnit_Dasharray || aOther.mValue.mCSSValueList,
@ -1591,6 +1731,16 @@ nsStyleAnimation::Value::SetAndAdoptCSSValuePairValue(
mValue.mCSSValuePair = aValuePair; // take ownership
}
void
nsStyleAnimation::Value::SetAndAdoptCSSRectValue(nsCSSRect *aRect, Unit aUnit)
{
FreeValue();
NS_ABORT_IF_FALSE(IsCSSRectUnit(aUnit), "bad unit");
NS_ABORT_IF_FALSE(aRect != nsnull, "value pairs may not be null");
mUnit = aUnit;
mValue.mCSSRect = aRect; // take ownership
}
void
nsStyleAnimation::Value::SetAndAdoptCSSValueListValue(
nsCSSValueList *aValueList, Unit aUnit)
@ -1610,6 +1760,8 @@ nsStyleAnimation::Value::FreeValue()
delete mValue.mCSSValueList;
} else if (IsCSSValuePairUnit(mUnit)) {
delete mValue.mCSSValuePair;
} else if (IsCSSRectUnit(mUnit)) {
delete mValue.mCSSRect;
} else if (IsStringUnit(mUnit)) {
NS_ABORT_IF_FALSE(mValue.mString, "expecting non-null string");
mValue.mString->Release();
@ -1641,6 +1793,8 @@ nsStyleAnimation::Value::operator==(const Value& aOther) const
return mValue.mColor == aOther.mValue.mColor;
case eUnit_CSSValuePair:
return *mValue.mCSSValuePair == *aOther.mValue.mCSSValuePair;
case eUnit_CSSRect:
return *mValue.mCSSRect == *aOther.mValue.mCSSRect;
case eUnit_Dasharray:
case eUnit_Shadow:
return nsCSSValueList::Equal(mValue.mCSSValueList,

View File

@ -56,6 +56,7 @@ class nsPresContext;
class nsStyleContext;
struct nsCSSValueList;
struct nsCSSValuePair;
struct nsCSSRect;
/**
* Utility class to handle animated style values
@ -234,6 +235,7 @@ public:
eUnit_Float,
eUnit_Color,
eUnit_CSSValuePair, // nsCSSValuePair* (never null)
eUnit_CSSRect, // nsCSSRect* (never null)
eUnit_Dasharray, // nsCSSValueList* (never null)
eUnit_Shadow, // nsCSSValueList* (may be null)
eUnit_UnparsedString // nsStringBuffer* (never null)
@ -248,6 +250,7 @@ public:
float mFloat;
nscolor mColor;
nsCSSValuePair* mCSSValuePair;
nsCSSRect* mCSSRect;
nsCSSValueList* mCSSValueList;
nsStringBuffer* mString;
} mValue;
@ -287,6 +290,10 @@ public:
NS_ASSERTION(IsCSSValuePairUnit(mUnit), "unit mismatch");
return mValue.mCSSValuePair;
}
nsCSSRect* GetCSSRectValue() const {
NS_ASSERTION(IsCSSRectUnit(mUnit), "unit mismatch");
return mValue.mCSSRect;
}
nsCSSValueList* GetCSSValueListValue() const {
NS_ASSERTION(IsCSSValueListUnit(mUnit), "unit mismatch");
return mValue.mCSSValueList;
@ -336,6 +343,7 @@ public:
// "SetAndAdopt*".
void SetAndAdoptCSSValueListValue(nsCSSValueList *aValue, Unit aUnit);
void SetAndAdoptCSSValuePairValue(nsCSSValuePair *aValue, Unit aUnit);
void SetAndAdoptCSSRectValue(nsCSSRect *aValue, Unit aUnit);
Value& operator=(const Value& aOther);
@ -356,6 +364,9 @@ public:
static PRBool IsCSSValuePairUnit(Unit aUnit) {
return aUnit == eUnit_CSSValuePair;
}
static PRBool IsCSSRectUnit(Unit aUnit) {
return aUnit == eUnit_CSSRect;
}
static PRBool IsCSSValueListUnit(Unit aUnit) {
return aUnit == eUnit_Dasharray || aUnit == eUnit_Shadow;
}

View File

@ -1302,14 +1302,7 @@ struct nsStyleDisplay {
// We guarantee that if mBinding is non-null, so are mBinding->mURI and
// mBinding->mOriginPrincipal.
nsRefPtr<nsCSSValue::URL> mBinding; // [reset]
#if 0
// XXX This is how it is defined in the CSS2 spec, but the errata
// changed it to be consistent with the positioning draft and how
// Nav and IE implement it
nsMargin mClip; // [reset] offsets from respective edge
#else
nsRect mClip; // [reset] offsets from upper-left border edge
#endif
float mOpacity; // [reset]
PRUint8 mDisplay; // [reset] see nsStyleConsts.h NS_STYLE_DISPLAY_*
PRUint8 mOriginalDisplay; // [reset] saved mDisplay for position:absolute/fixed

View File

@ -59,6 +59,7 @@ var supported_properties = {
"-moz-column-rule-color": [ test_color_transition ],
"-moz-column-rule-width": [ test_length_transition ],
"-moz-column-width": [ test_length_transition ],
"-moz-image-region": [ test_rect_transition ],
"-moz-outline-radius-bottomleft": [ test_radius_transition ],
"-moz-outline-radius-bottomright": [ test_radius_transition ],
"-moz-outline-radius-topleft": [ test_radius_transition ],
@ -76,6 +77,7 @@ var supported_properties = {
"border-top-color": [ test_color_transition ],
"border-top-width": [ test_length_transition ],
"bottom": [ test_length_transition, test_percent_transition ],
"clip": [ test_rect_transition ],
"color": [ test_color_transition ],
"fill": [ test_color_transition ],
"fill-opacity" : [ test_float_zeroToOne_transition ],
@ -526,6 +528,26 @@ function test_length_percent_pair_transition(prop) {
"length-valued property " + prop + ": interpolation of lengths");
}
function test_rect_transition(prop) {
div.style.setProperty("-moz-transition-property", "none", "");
div.style.setProperty(prop, "rect(4px, 16px, 12px, 8px)", "");
is(cs.getPropertyValue(prop), "rect(4px, 16px, 12px, 8px)",
"rect-valued property " + prop + ": computed value before transition");
div.style.setProperty("-moz-transition-property", prop, "");
div.style.setProperty(prop, "rect(0px, 6px, 4px, 2px)", "");
is(cs.getPropertyValue(prop), "rect(2px, 11px, 8px, 5px)",
"rect-valued property " + prop + ": interpolation of rects");
if (prop == "clip") {
div.style.setProperty(prop, "rect(0px, 6px, 4px, auto)", "");
is(cs.getPropertyValue(prop), "rect(0px, 6px, 4px, auto)",
"rect-valued property " + prop + ": can't interpolate auto components");
div.style.setProperty(prop, "rect(0px, 6px, 4px, 2px)", "");
}
div.style.setProperty(prop, "auto", "");
is(cs.getPropertyValue(prop), "auto",
"rect-valued property " + prop + ": can't interpolate auto components");
}
</script>
</pre>
</body>