Implement nsStyleAnimation::Add and Interpolate using the same code underneath. (Bug 523193) r=dholbert sr=bzbarsky

This commit is contained in:
L. David Baron 2009-10-20 07:46:16 -04:00
Родитель 8461beec27
Коммит d035804a7a
2 изменённых файлов: 69 добавлений и 116 удалений

Просмотреть файл

@ -88,83 +88,6 @@ GetCommonUnit(nsStyleAnimation::Unit aFirstUnit,
// CLASS METHODS // 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(Value& aDest, const Value& aValueToAdd,
PRUint32 aCount)
{
Unit commonUnit = GetCommonUnit(aDest.GetUnit(), aValueToAdd.GetUnit());
PRBool success = PR_TRUE;
switch (commonUnit) {
case eUnit_Coord: {
nscoord destCoord = aDest.GetCoordValue();
nscoord valueToAddCoord = aValueToAdd.GetCoordValue();
destCoord += aCount * valueToAddCoord;
aDest.SetCoordValue(destCoord);
break;
}
case eUnit_Percent: {
float destPct = aDest.GetPercentValue();
float valueToAddPct = aValueToAdd.GetPercentValue();
destPct += aCount * valueToAddPct;
aDest.SetPercentValue(destPct);
break;
}
case eUnit_Float: {
float destFloat = aDest.GetFloatValue();
float valueToAddFloat = aValueToAdd.GetFloatValue();
destFloat += aCount * valueToAddFloat;
aDest.SetFloatValue(destFloat);
break;
}
case eUnit_Color: {
// Since nscolor doesn't allow out-of-sRGB values, by-animations
// of colors don't make much sense in our implementation.
// FIXME (bug 515919): 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 eUnit_Null:
success = PR_FALSE;
break;
default:
NS_NOTREACHED("Can't add Values using the given common unit");
success = PR_FALSE;
break;
}
return success;
}
PRBool PRBool
nsStyleAnimation::ComputeDistance(const Value& aStartValue, nsStyleAnimation::ComputeDistance(const Value& aStartValue,
const Value& aEndValue, const Value& aEndValue,
@ -240,15 +163,23 @@ nsStyleAnimation::ComputeDistance(const Value& aStartValue,
return success; return success;
} }
#define MAX_PACKED_COLOR_COMPONENT 255
inline PRUint8 ClampColor(double aColor)
{
if (aColor >= MAX_PACKED_COLOR_COMPONENT)
return MAX_PACKED_COLOR_COMPONENT;
if (aColor <= 0.0)
return 0;
return NSToIntRound(aColor);
}
PRBool PRBool
nsStyleAnimation::Interpolate(const Value& aStartValue, nsStyleAnimation::AddWeighted(double aCoeff1, const Value& aValue1,
const Value& aEndValue, double aCoeff2, const Value& aValue2,
double aPortion,
Value& aResultValue) Value& aResultValue)
{ {
NS_ABORT_IF_FALSE(aPortion >= 0.0 && aPortion <= 1.0, Unit commonUnit = GetCommonUnit(aValue1.GetUnit(), aValue2.GetUnit());
"aPortion out of bounds");
Unit commonUnit = GetCommonUnit(aStartValue.GetUnit(), aEndValue.GetUnit());
// Maybe need a followup method to convert the inputs into the common // Maybe need a followup method to convert the inputs into the common
// unit-type, if they don't already match it. (Or would it make sense to do // unit-type, if they don't already match it. (Or would it make sense to do
// that in GetCommonUnit? in which case maybe ConvertToCommonUnit would be // that in GetCommonUnit? in which case maybe ConvertToCommonUnit would be
@ -257,31 +188,26 @@ nsStyleAnimation::Interpolate(const Value& aStartValue,
PRBool success = PR_TRUE; PRBool success = PR_TRUE;
switch (commonUnit) { switch (commonUnit) {
case eUnit_Coord: { case eUnit_Coord: {
nscoord startCoord = aStartValue.GetCoordValue(); aResultValue.SetCoordValue(NSToCoordRound(
nscoord endCoord = aEndValue.GetCoordValue(); aCoeff1 * aValue1.GetCoordValue() +
nscoord resultCoord = startCoord + aCoeff2 * aValue2.GetCoordValue()));
NSToCoordRound(aPortion * (endCoord - startCoord));
aResultValue.SetCoordValue(resultCoord);
break; break;
} }
case eUnit_Percent: { case eUnit_Percent: {
float startPct = aStartValue.GetPercentValue(); aResultValue.SetPercentValue(
float endPct = aEndValue.GetPercentValue(); aCoeff1 * aValue1.GetPercentValue() +
float resultPct = startPct + aPortion * (endPct - startPct); aCoeff2 * aValue2.GetPercentValue());
aResultValue.SetPercentValue(resultPct);
break; break;
} }
case eUnit_Float: { case eUnit_Float: {
float startFloat = aStartValue.GetFloatValue(); aResultValue.SetFloatValue(
float endFloat = aEndValue.GetFloatValue(); aCoeff1 * aValue1.GetFloatValue() +
float resultFloat = startFloat + aPortion * (endFloat - startFloat); aCoeff2 * aValue2.GetFloatValue());
aResultValue.SetFloatValue(resultFloat);
break; break;
} }
case eUnit_Color: { case eUnit_Color: {
double inv = 1.0 - aPortion; nscolor color1 = aValue1.GetColorValue();
nscolor startColor = aStartValue.GetColorValue(); nscolor color2 = aValue2.GetColorValue();
nscolor endColor = aEndValue.GetColorValue();
// FIXME (spec): The CSS transitions spec doesn't say whether // FIXME (spec): The CSS transitions spec doesn't say whether
// colors are premultiplied, but things work better when they are, // colors are premultiplied, but things work better when they are,
// so use premultiplication. Spec issue is still open per // so use premultiplication. Spec issue is still open per
@ -289,25 +215,28 @@ nsStyleAnimation::Interpolate(const Value& aStartValue,
// To save some math, scale the alpha down to a 0-1 scale, but // To save some math, scale the alpha down to a 0-1 scale, but
// leave the color components on a 0-255 scale. // leave the color components on a 0-255 scale.
double startA = NS_GET_A(startColor) * (1.0 / 255.0); double A1 = NS_GET_A(color1) * (1.0 / 255.0);
double startR = NS_GET_R(startColor) * startA; double R1 = NS_GET_R(color1) * A1;
double startG = NS_GET_G(startColor) * startA; double G1 = NS_GET_G(color1) * A1;
double startB = NS_GET_B(startColor) * startA; double B1 = NS_GET_B(color1) * A1;
double endA = NS_GET_A(endColor) * (1.0 / 255.0); double A2 = NS_GET_A(color2) * (1.0 / 255.0);
double endR = NS_GET_R(endColor) * endA; double R2 = NS_GET_R(color2) * A2;
double endG = NS_GET_G(endColor) * endA; double G2 = NS_GET_G(color2) * A2;
double endB = NS_GET_B(endColor) * endA; double B2 = NS_GET_B(color2) * A2;
double resAf = (startA * inv + endA * aPortion); double Aresf = (A1 * aCoeff1 + A2 * aCoeff2);
nscolor resultColor; nscolor resultColor;
if (resAf == 0.0) { if (Aresf <= 0.0) {
resultColor = NS_RGBA(0, 0, 0, 0); resultColor = NS_RGBA(0, 0, 0, 0);
} else { } else {
double factor = 1.0 / resAf; if (Aresf > 1.0) {
PRUint8 resA = NSToIntRound(resAf * 255.0); Aresf = 1.0;
PRUint8 resR = NSToIntRound((startR * inv + endR * aPortion) * factor); }
PRUint8 resG = NSToIntRound((startG * inv + endG * aPortion) * factor); double factor = 1.0 / Aresf;
PRUint8 resB = NSToIntRound((startB * inv + endB * aPortion) * factor); PRUint8 Ares = NSToIntRound(Aresf * 255.0);
resultColor = NS_RGBA(resR, resG, resB, resA); PRUint8 Rres = ClampColor((R1 * aCoeff1 + R2 * aCoeff2) * factor);
PRUint8 Gres = ClampColor((G1 * aCoeff1 + G2 * aCoeff2) * factor);
PRUint8 Bres = ClampColor((B1 * aCoeff1 + B2 * aCoeff2) * factor);
resultColor = NS_RGBA(Rres, Gres, Bres, Ares);
} }
aResultValue.SetColorValue(resultColor); aResultValue.SetColorValue(resultColor);
break; break;

Просмотреть файл

@ -75,7 +75,9 @@ public:
* @return PR_TRUE on success, PR_FALSE on failure. * @return PR_TRUE on success, PR_FALSE on failure.
*/ */
static PRBool Add(Value& aDest, const Value& aValueToAdd, static PRBool Add(Value& aDest, const Value& aValueToAdd,
PRUint32 aCount); PRUint32 aCount) {
return AddWeighted(1.0, aDest, aCount, aValueToAdd, aDest);
}
/** /**
* Calculates a measure of 'distance' between two values. * Calculates a measure of 'distance' between two values.
@ -113,6 +115,28 @@ public:
static PRBool Interpolate(const Value& aStartValue, static PRBool Interpolate(const Value& aStartValue,
const Value& aEndValue, const Value& aEndValue,
double aPortion, double aPortion,
Value& aResultValue) {
NS_ABORT_IF_FALSE(0.0 <= aPortion && aPortion <= 1.0, "out of range");
return AddWeighted(1.0 - aPortion, aStartValue, aPortion, aEndValue,
aResultValue);
}
/**
* Does the calculation:
* aResultValue = aCoeff1 * aValue1 + aCoeff2 * aValue2
*
* @param [out] aResultValue The resulting interpolated value. May be
* the same as aValue1 or aValue2.
* @return PR_TRUE on success, PR_FALSE on failure.
*
* NOTE: Current callers always pass aCoeff1 and aCoeff2 >= 0. They
* are currently permitted to be negative; however, if, as we add
* support more value types types, we find that this causes
* difficulty, we might change this to restrict them to being
* positive.
*/
static PRBool AddWeighted(double aCoeff1, const Value& aValue1,
double aCoeff2, const Value& aValue2,
Value& aResultValue); Value& aResultValue);
// Type-conversion methods // Type-conversion methods