Bug 1299741 part 10 - Implement interpolation between numeric color and currentcolor. r=birtles
MozReview-Commit-ID: CAQmTpCznaa
--- a/gfx/src/nsColor.h
+++ b/gfx/src/nsColor.h
@@ -31,16 +31,22 @@ typedef uint32_t nscolor;
// Extract color components from nscolor
#define NS_GET_R(_rgba) ((uint8_t) ((_rgba) & 0xff))
#define NS_GET_G(_rgba) ((uint8_t) (((_rgba) >> 8) & 0xff))
#define NS_GET_B(_rgba) ((uint8_t) (((_rgba) >> 16) & 0xff))
#define NS_GET_A(_rgba) ((uint8_t) (((_rgba) >> 24) & 0xff))
namespace mozilla {
+inline nscolor
+ColorWithAlpha(nscolor aColor, uint_fast8_t aAlpha)
+{
+ return (aColor & 0x00ffffff) | (aAlpha << 24);
+}
+
template<typename T>
inline uint_fast8_t ClampColor(T aColor)
{
if (aColor >= 255) {
return 255;
}
if (aColor <= 0) {
return 0;
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -63,16 +63,25 @@ GetCommonUnit(nsCSSPropertyID aProperty,
aFirstUnit == StyleAnimationValue::eUnit_Percent ||
aFirstUnit == StyleAnimationValue::eUnit_Calc) &&
(aSecondUnit == StyleAnimationValue::eUnit_Coord ||
aSecondUnit == StyleAnimationValue::eUnit_Percent ||
aSecondUnit == StyleAnimationValue::eUnit_Calc)) {
// We can use calc() as the common unit.
return StyleAnimationValue::eUnit_Calc;
}
+ if ((aFirstUnit == StyleAnimationValue::eUnit_Color ||
+ aFirstUnit == StyleAnimationValue::eUnit_CurrentColor ||
+ aFirstUnit == StyleAnimationValue::eUnit_ComplexColor) &&
+ (aSecondUnit == StyleAnimationValue::eUnit_Color ||
+ aSecondUnit == StyleAnimationValue::eUnit_CurrentColor ||
+ aSecondUnit == StyleAnimationValue::eUnit_ComplexColor)) {
+ // We can use complex color as the common unit.
+ return StyleAnimationValue::eUnit_ComplexColor;
+ }
return StyleAnimationValue::eUnit_Null;
}
return aFirstUnit;
}
static
nsCSSUnit
GetCommonUnit(nsCSSPropertyID aProperty,
@@ -293,16 +302,30 @@ FragmentOrURLToURLValue(FragmentOrURL* a
RefPtr<nsStringBuffer> uriStringBuffer = nsCSSValue::BufferFromString(path);
RefPtr<mozilla::css::URLValue> result =
new mozilla::css::URLValue(aUrl->GetSourceURL(), uriStringBuffer,
aDoc->GetDocumentURI(), aDoc->NodePrincipal());
return result.forget();
}
+static StyleComplexColor
+ExtractComplexColorValue(const StyleAnimationValue& aValue)
+{
+ if (aValue.GetUnit() == StyleAnimationValue::eUnit_Color) {
+ return StyleComplexColor::FromColor(aValue.GetColorValue());
+ }
+ if (aValue.GetUnit() == StyleAnimationValue::eUnit_CurrentColor) {
+ return StyleComplexColor::CurrentColor();
+ }
+ MOZ_ASSERT(aValue.GetUnit() == StyleAnimationValue::eUnit_ComplexColor,
+ "unexpected unit");
+ return aValue.GetComplexColorValue();
+}
+
// Like nsStyleCoord::CalcValue, but with length in float pixels instead
// of nscoord.
struct PixelCalcValue
{
float mLength, mPercent;
bool mHasPercent;
};
@@ -526,17 +549,16 @@ StyleAnimationValue::ComputeDistance(nsC
switch (commonUnit) {
case eUnit_Null:
case eUnit_Auto:
case eUnit_None:
case eUnit_Normal:
case eUnit_UnparsedString:
case eUnit_URL:
- case eUnit_CurrentColor:
case eUnit_DiscreteCSSValue:
return false;
case eUnit_Enumerated:
switch (aProperty) {
case eCSSProperty_font_stretch: {
// just like eUnit_Integer.
int32_t startInt = aStartValue.GetIntValue();
@@ -585,16 +607,54 @@ StyleAnimationValue::ComputeDistance(nsC
aDistance = Abs(double(endFloat) - double(startFloat));
return true;
}
case eUnit_Color: {
aDistance = ComputeColorDistance(aStartValue.GetColorValue(),
aEndValue.GetColorValue());
return true;
}
+ case eUnit_CurrentColor: {
+ aDistance = 0;
+ return true;
+ }
+ case eUnit_ComplexColor: {
+ StyleComplexColor color1 = ExtractComplexColorValue(aStartValue);
+ StyleComplexColor color2 = ExtractComplexColorValue(aEndValue);
+
+ // Common case is interpolating between a color and a currentcolor.
+ if (color1.IsNumericColor() && color2.IsCurrentColor()) {
+ double dist = ComputeColorDistance(color1.mColor, NS_RGBA(0, 0, 0, 0));
+ aDistance = sqrt(dist * dist + 1);
+ return true;
+ }
+ if (color1.IsCurrentColor() && color2.IsNumericColor()) {
+ double dist = ComputeColorDistance(NS_RGBA(0, 0, 0, 0), color2.mColor);
+ aDistance = sqrt(dist * dist + 1);
+ return true;
+ }
+
+ // We shouldn't ever get here but the following code may still be
+ // useful in the future, and be a fallback if the assertion fails.
+ MOZ_ASSERT_UNREACHABLE("We shouldn't get here as we only call "
+ "ComputeDistance on pre-interpolation values");
+
+ // Compute distance based on colors premultipled with
+ // the non-foreground ratio.
+ auto alpha1 = RoundingDivideBy255(NS_GET_A(color1.mColor) *
+ (255 - color1.mForegroundRatio));
+ auto alpha2 = RoundingDivideBy255(NS_GET_A(color2.mColor) *
+ (255 - color2.mForegroundRatio));
+ double dist = ComputeColorDistance(ColorWithAlpha(color1.mColor, alpha1),
+ ColorWithAlpha(color2.mColor, alpha2));
+ double diffRatio = (1.0 / 255.0) * color1.mForegroundRatio -
+ (1.0 / 255.0) * color2.mForegroundRatio;
+ aDistance = sqrt(dist * dist + diffRatio * diffRatio);
+ return true;
+ }
case eUnit_Calc: {
PixelCalcValue v1 = ExtractCalcValue(aStartValue);
PixelCalcValue v2 = ExtractCalcValue(aEndValue);
float difflen = v2.mLength - v1.mLength;
float diffpct = v2.mPercent - v1.mPercent;
aDistance = sqrt(difflen * difflen + diffpct * diffpct);
return true;
}
@@ -2313,17 +2373,16 @@ StyleAnimationValue::AddWeighted(nsCSSPr
switch (commonUnit) {
case eUnit_Null:
case eUnit_Auto:
case eUnit_None:
case eUnit_Normal:
case eUnit_UnparsedString:
case eUnit_URL:
- case eUnit_CurrentColor:
case eUnit_DiscreteCSSValue:
return false;
case eUnit_Enumerated:
switch (aProperty) {
case eCSSProperty_font_stretch: {
// Animate just like eUnit_Integer.
int32_t result = floor(aCoeff1 * double(aValue1.GetIntValue()) +
@@ -2396,16 +2455,56 @@ StyleAnimationValue::AddWeighted(nsCSSPr
}
case eUnit_Color: {
nscolor color1 = aValue1.GetColorValue();
nscolor color2 = aValue2.GetColorValue();
aResultValue.SetColorValue(AddWeightedColors(aCoeff1, color1,
aCoeff2, color2));
return true;
}
+ case eUnit_CurrentColor: {
+ aResultValue.SetCurrentColorValue();
+ return true;
+ }
+ case eUnit_ComplexColor: {
+ StyleComplexColor color1 = ExtractComplexColorValue(aValue1);
+ StyleComplexColor color2 = ExtractComplexColorValue(aValue2);
+ StyleComplexColor result;
+ // Common case is interpolating between a color and a currentcolor.
+ if (color1.IsNumericColor() && color2.IsCurrentColor()) {
+ result.mColor = color1.mColor;
+ result.mForegroundRatio = ClampColor(aCoeff2 * 255);
+ } else if (color1.IsCurrentColor() && color2.IsNumericColor()) {
+ result.mColor = color2.mColor;
+ result.mForegroundRatio = ClampColor(aCoeff1 * 255);
+ } else {
+ uint32_t ratio1 = 255 - color1.mForegroundRatio;
+ uint32_t ratio2 = 255 - color2.mForegroundRatio;
+ // Premultipled alpha channel with the non-foreground ratio.
+ auto alpha1 = RoundingDivideBy255(NS_GET_A(color1.mColor) * ratio1);
+ auto alpha2 = RoundingDivideBy255(NS_GET_A(color2.mColor) * ratio2);
+ nscolor resultColor =
+ AddWeightedColors(aCoeff1, ColorWithAlpha(color1.mColor, alpha1),
+ aCoeff2, ColorWithAlpha(color2.mColor, alpha2));
+ auto resultRatio = ClampColor(color1.mForegroundRatio * aCoeff1 +
+ color2.mForegroundRatio * aCoeff2);
+ if (resultRatio == 255) {
+ result = StyleComplexColor::CurrentColor();
+ } else {
+ auto resultAlpha = NS_GET_A(resultColor) * 255 / (255 - resultRatio);
+ if (resultAlpha > 255) {
+ resultAlpha = 255;
+ }
+ result.mColor = ColorWithAlpha(resultColor, resultAlpha);
+ result.mForegroundRatio = resultRatio;
+ }
+ }
+ aResultValue.SetComplexColorValue(result);
+ return true;
+ }
case eUnit_Calc: {
PixelCalcValue v1 = ExtractCalcValue(aValue1);
PixelCalcValue v2 = ExtractCalcValue(aValue2);
double len = aCoeff1 * v1.mLength + aCoeff2 * v2.mLength;
double pct = aCoeff1 * v1.mPercent + aCoeff2 * v2.mPercent;
bool hasPct = (aCoeff1 != 0.0 && v1.mHasPercent) ||
(aCoeff2 != 0.0 && v2.mHasPercent);
nsCSSValue *val = new nsCSSValue();