Add support for animation of color values (conversion of nscolor values to nsStyleCoord and animation of eStyleUnit_Color nsStyleCoords) to nsStyleAnimation. (Bug 504652) r=dholbert sr=bzbarsky

This commit is contained in:
L. David Baron 2009-09-11 06:46:36 -04:00
parent 587ac05e42
commit 2088a9b2f5
3 changed files with 143 additions and 12 deletions

View File

@ -460,8 +460,8 @@ CSS_PROP_BACKGROUND(
mBackColor,
eCSSType_Value,
nsnull,
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
offsetof(nsStyleBackground, mBackgroundColor),
eStyleAnimType_Color)
CSS_PROP_BACKGROUND(
background-image,
background_image,
@ -565,6 +565,8 @@ CSS_PROP_BORDER(
mBorderColor.mBottom,
eCSSType_Value,
kBorderColorKTable,
// FIXME: should be animatable (but currently involves complex split
// between color and an extra bit on the style, all private members)
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
CSS_PROP_BORDER(
@ -708,6 +710,8 @@ CSS_PROP_BORDER(
mBorderColor.mLeft,
eCSSType_Value,
kBorderColorKTable,
// FIXME: should be animatable (but currently involves complex split
// between color and an extra bit on the style, all private members)
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
CSS_PROP_BORDER(
@ -854,6 +858,8 @@ CSS_PROP_BORDER(
mBorderColor.mRight,
eCSSType_Value,
kBorderColorKTable,
// FIXME: should be animatable (but currently involves complex split
// between color and an extra bit on the style, all private members)
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
CSS_PROP_BORDER(
@ -1069,6 +1075,8 @@ CSS_PROP_BORDER(
mBorderColor.mTop,
eCSSType_Value,
kBorderColorKTable,
// FIXME: should be animatable (but currently involves complex split
// between color and an extra bit on the style, all private members)
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
CSS_PROP_BORDER(
@ -1188,8 +1196,8 @@ CSS_PROP_COLOR(
mColor,
eCSSType_Value,
nsnull,
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
offsetof(nsStyleColor, mColor),
eStyleAnimType_Color)
CSS_PROP_COLUMN(
-moz-column-count,
_moz_column_count,
@ -1237,8 +1245,8 @@ CSS_PROP_COLUMN(
mColumnRuleColor,
eCSSType_Value,
nsnull,
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
offsetof(nsStyleColumn, mColumnRuleColor),
eStyleAnimType_Color)
CSS_PROP_COLUMN(
-moz-column-rule-style,
_moz_column_rule_style,
@ -1836,6 +1844,8 @@ CSS_PROP_OUTLINE(
mOutlineColor,
eCSSType_Value,
kOutlineColorKTable,
// FIXME: should be animatable (but currently involves complex split
// between color and an extra bit on the style, all private members)
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
CSS_PROP_OUTLINE(
@ -2794,8 +2804,8 @@ CSS_PROP_SVGRESET(
mFloodColor,
eCSSType_Value,
nsnull,
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
offsetof(nsStyleSVGReset, mFloodColor),
eStyleAnimType_Color)
CSS_PROP_SVGRESET(
flood-opacity,
flood_opacity,
@ -2827,8 +2837,8 @@ CSS_PROP_SVGRESET(
mLightingColor,
eCSSType_Value,
nsnull,
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
offsetof(nsStyleSVGReset, mLightingColor),
eStyleAnimType_Color)
CSS_PROP_SHORTHAND(
marker,
marker,
@ -2898,8 +2908,8 @@ CSS_PROP_SVGRESET(
mStopColor,
eCSSType_Value,
nsnull,
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
offsetof(nsStyleSVGReset, mStopColor),
eStyleAnimType_Color)
CSS_PROP_SVGRESET(
stop-opacity,
stop_opacity,

View File

@ -82,6 +82,9 @@ enum nsStyleAnimType {
// nscoord values
eStyleAnimType_nscoord,
// nscolor values
eStyleAnimType_Color,
// property not animatable
eStyleAnimType_None
};

View File

@ -53,6 +53,7 @@
#include "nsCSSDataBlock.h"
#include "nsCSSDeclaration.h"
#include "prlog.h"
#include <math.h>
// HELPER METHODS
// --------------
@ -93,6 +94,15 @@ GetCommonUnit(nsStyleUnit aFirstUnit,
// CLASS METHODS
// -------------
#define MAX_PACKED_COLOR_COMPONENT 255
inline PRUint8 ClampColor(PRUint32 aColor)
{
if (aColor >= MAX_PACKED_COLOR_COMPONENT)
return MAX_PACKED_COLOR_COMPONENT;
return aColor;
}
PRBool
nsStyleAnimation::Add(nsStyleCoord& aDest, const nsStyleCoord& aValueToAdd,
PRUint32 aCount)
@ -115,6 +125,35 @@ nsStyleAnimation::Add(nsStyleCoord& aDest, const nsStyleCoord& aValueToAdd,
aDest.SetPercentValue(destPct);
break;
}
case eStyleUnit_Color: {
// Since nscolor doesn't allow out-of-sRGB values, by-animations
// of colors don't make much sense in our implementation.
// FIXME: Animation of colors should really use floating point
// colors (and when it does, ClampColor and the clamping of aCount
// should go away).
// Also, given RGBA colors, it's not clear whether we want
// premultiplication. Probably we don't, given that's hard to
// premultiply aValueToAdd since it's a difference rather than a
// value.
nscolor destColor = aDest.GetColorValue();
nscolor colorToAdd = aValueToAdd.GetColorValue();
if (aCount > MAX_PACKED_COLOR_COMPONENT) {
// Given that we're using integers and clamping at 255, we can
// clamp aCount to 255 since that's enough to saturate if we're
// multiplying it by anything nonzero.
aCount = MAX_PACKED_COLOR_COMPONENT;
}
PRUint8 resultR =
ClampColor(NS_GET_R(destColor) + aCount * NS_GET_R(colorToAdd));
PRUint8 resultG =
ClampColor(NS_GET_G(destColor) + aCount * NS_GET_G(colorToAdd));
PRUint8 resultB =
ClampColor(NS_GET_B(destColor) + aCount * NS_GET_B(colorToAdd));
PRUint8 resultA =
ClampColor(NS_GET_A(destColor) + aCount * NS_GET_A(colorToAdd));
aDest.SetColorValue(NS_RGBA(resultR, resultG, resultB, resultA));
break;
}
case eStyleUnit_Null:
NS_WARNING("Unable to find a common unit for given values");
success = PR_FALSE;
@ -149,6 +188,43 @@ nsStyleAnimation::ComputeDistance(const nsStyleCoord& aStartValue,
aDistance = fabs(double(endPct - startPct));
break;
}
case eStyleUnit_Color: {
// http://www.w3.org/TR/smil-animation/#animateColorElement says
// that we should use Euclidean RGB cube distance. However, we
// have to extend that to RGBA. For now, we'll just use the
// Euclidean distance in the (part of the) 4-cube of premultiplied
// colors.
// FIXME (spec): The CSS transitions spec doesn't say whether
// colors are premultiplied, but things work better when they are,
// so use premultiplication. Spec issue is still open per
// http://lists.w3.org/Archives/Public/www-style/2009Jul/0050.html
nscolor startColor = aStartValue.GetColorValue();
nscolor endColor = aEndValue.GetColorValue();
// Get a color component on a 0-1 scale, which is much easier to
// deal with when working with alpha.
#define GET_COMPONENT(component_, color_) \
(NS_GET_##component_(color_) * (1.0 / 255.0))
double startA = GET_COMPONENT(A, startColor);
double startR = GET_COMPONENT(R, startColor) * startA;
double startG = GET_COMPONENT(G, startColor) * startA;
double startB = GET_COMPONENT(B, startColor) * startA;
double endA = GET_COMPONENT(A, endColor);
double endR = GET_COMPONENT(R, endColor) * endA;
double endG = GET_COMPONENT(G, endColor) * endA;
double endB = GET_COMPONENT(B, endColor) * endA;
#undef GET_COMPONENT
double diffA = startA - endA;
double diffR = startR - endR;
double diffG = startG - endG;
double diffB = startB - endB;
aDistance = sqrt(diffA * diffA + diffR * diffR +
diffG * diffG + diffB * diffB);
break;
}
case eStyleUnit_Null:
NS_WARNING("Unable to find a common unit for given values");
success = PR_FALSE;
@ -193,6 +269,40 @@ nsStyleAnimation::Interpolate(const nsStyleCoord& aStartValue,
aResultValue.SetPercentValue(resultPct);
break;
}
case eStyleUnit_Color: {
double inv = 1.0 - aPortion;
nscolor startColor = aStartValue.GetColorValue();
nscolor endColor = aEndValue.GetColorValue();
// FIXME (spec): The CSS transitions spec doesn't say whether
// colors are premultiplied, but things work better when they are,
// so use premultiplication. Spec issue is still open per
// http://lists.w3.org/Archives/Public/www-style/2009Jul/0050.html
// To save some math, scale the alpha down to a 0-1 scale, but
// leave the color components on a 0-255 scale.
double startA = NS_GET_A(startColor) * (1.0 / 255.0);
double startR = NS_GET_R(startColor) * startA;
double startG = NS_GET_G(startColor) * startA;
double startB = NS_GET_B(startColor) * startA;
double endA = NS_GET_A(endColor) * (1.0 / 255.0);
double endR = NS_GET_R(endColor) * endA;
double endG = NS_GET_G(endColor) * endA;
double endB = NS_GET_B(endColor) * endA;
double resAf = (startA * inv + endA * aPortion);
nscolor resultColor;
if (resAf == 0.0) {
resultColor = NS_RGBA(0, 0, 0, 0);
} else {
double factor = 1.0 / resAf;
PRUint8 resA = NSToIntRound(resAf * 255.0);
PRUint8 resR = NSToIntRound((startR * inv + endR * aPortion) * factor);
PRUint8 resG = NSToIntRound((startG * inv + endG * aPortion) * factor);
PRUint8 resB = NSToIntRound((startB * inv + endB * aPortion) * factor);
resultColor = NS_RGBA(resR, resG, resB, resA);
}
aResultValue.SetColorValue(resultColor);
break;
}
case eStyleUnit_Null:
NS_WARNING("Unable to find a common unit for given values");
success = PR_FALSE;
@ -344,6 +454,10 @@ nsStyleAnimation::ExtractComputedValue(nsCSSProperty aProperty,
aComputedValue.SetCoordValue(*static_cast<const nscoord*>(
StyleDataAtOffset(styleStruct, ssOffset)));
return PR_TRUE;
case eStyleAnimType_Color:
aComputedValue.SetColorValue(*static_cast<const nscolor*>(
StyleDataAtOffset(styleStruct, ssOffset)));
return PR_TRUE;
case eStyleAnimType_None:
NS_NOTREACHED("shouldn't use on non-animatable properties");
}
@ -403,6 +517,10 @@ nsStyleAnimation::StoreComputedValue(nsCSSProperty aProperty,
}
}
return PR_TRUE;
case eStyleAnimType_Color:
*static_cast<nscolor*>(StyleDataAtOffset(aStyleStruct, ssOffset)) =
aComputedValue.GetColorValue();
return PR_TRUE;
case eStyleAnimType_None:
NS_NOTREACHED("shouldn't use on non-animatable properties");
}