Bug 1299741 part 7 - Support storing ComplexColor in nsCSSValue and StyleAnimationValue. r=heycam
This is a complete rewrite of the original part 8. Instead of storing
the ratio in mValueExtra, all values are stored in a struct in heap,
so that we support range outside [0.0, 1.0] in computation.
MozReview-Commit-ID: 7xUZSgQE5vA
--- a/layout/style/StyleAnimationValue.cpp
+++ b/layout/style/StyleAnimationValue.cpp
@@ -3206,16 +3206,21 @@ StyleAnimationValue::UncomputeValue(nsCS
(unit == eUnit_ObjectPosition &&
val->GetUnit() == eCSSUnit_Array) ||
(unit == eUnit_URL && val->GetUnit() == eCSSUnit_URL) ||
unit == eUnit_DiscreteCSSValue,
"unexpected unit");
aSpecifiedValue = *val;
break;
}
+ case eUnit_ComplexColor: {
+ aSpecifiedValue.SetComplexColorValue(
+ do_AddRef(aComputedValue.mValue.mComplexColor));
+ break;
+ }
case eUnit_CSSValuePair: {
// Rule node processing expects pair values to be collapsed to a
// single value if both halves would be equal, for most but not
// all properties. At present, all animatable properties that
// use pairs do expect collapsing.
const nsCSSValuePair* pair = aComputedValue.GetCSSValuePairValue();
if (pair->mXValue == pair->mYValue) {
aSpecifiedValue = pair->mXValue;
@@ -4512,16 +4517,21 @@ StyleAnimationValue::operator=(const Sty
"value pair lists may not be null");
mValue.mCSSValuePairList = aOther.mValue.mCSSValuePairList->Clone();
break;
case eUnit_UnparsedString:
MOZ_ASSERT(aOther.mValue.mString, "expecting non-null string");
mValue.mString = aOther.mValue.mString;
mValue.mString->AddRef();
break;
+ case eUnit_ComplexColor:
+ MOZ_ASSERT(aOther.mValue.mComplexColor);
+ mValue.mComplexColor = aOther.mValue.mComplexColor;
+ mValue.mComplexColor->AddRef();
+ break;
}
return *this;
}
void
StyleAnimationValue::SetNormalValue()
{
@@ -4590,16 +4600,37 @@ StyleAnimationValue::SetColorValue(nscol
void
StyleAnimationValue::SetCurrentColorValue()
{
FreeValue();
mUnit = eUnit_CurrentColor;
}
void
+StyleAnimationValue::SetComplexColorValue(const StyleComplexColor& aColor)
+{
+ if (aColor.IsCurrentColor()) {
+ SetCurrentColorValue();
+ } else if (aColor.IsNumericColor()) {
+ SetColorValue(aColor.mColor);
+ } else {
+ SetComplexColorValue(do_AddRef(new ComplexColorValue(aColor)));
+ }
+}
+
+void
+StyleAnimationValue::SetComplexColorValue(
+ already_AddRefed<ComplexColorValue> aValue)
+{
+ FreeValue();
+ mUnit = eUnit_ComplexColor;
+ mValue.mComplexColor = aValue.take();
+}
+
+void
StyleAnimationValue::SetUnparsedStringValue(const nsString& aString)
{
FreeValue();
mUnit = eUnit_UnparsedString;
mValue.mString = nsCSSValue::BufferFromString(aString).take();
}
void
@@ -4707,16 +4738,18 @@ StyleAnimationValue::FreeValue()
delete mValue.mCSSRect;
} else if (IsCSSValuePairListUnit(mUnit)) {
delete mValue.mCSSValuePairList;
} else if (IsCSSValueArrayUnit(mUnit)) {
mValue.mCSSValueArray->Release();
} else if (IsStringUnit(mUnit)) {
MOZ_ASSERT(mValue.mString, "expecting non-null string");
mValue.mString->Release();
+ } else if (mUnit == eUnit_ComplexColor) {
+ mValue.mComplexColor->Release();
}
}
bool
StyleAnimationValue::operator==(const StyleAnimationValue& aOther) const
{
if (mUnit != aOther.mUnit) {
return false;
@@ -4763,13 +4796,15 @@ StyleAnimationValue::operator==(const St
case eUnit_Transform:
return *mValue.mCSSValueSharedList == *aOther.mValue.mCSSValueSharedList;
case eUnit_CSSValuePairList:
return nsCSSValuePairList::Equal(mValue.mCSSValuePairList,
aOther.mValue.mCSSValuePairList);
case eUnit_UnparsedString:
return (NS_strcmp(GetStringBufferValue(),
aOther.GetStringBufferValue()) == 0);
+ case eUnit_ComplexColor:
+ return *mValue.mComplexColor == *aOther.mValue.mComplexColor;
}
NS_NOTREACHED("incomplete case");
return false;
}
--- a/layout/style/StyleAnimationValue.h
+++ b/layout/style/StyleAnimationValue.h
@@ -315,16 +315,17 @@ public:
// Enumerated to Visibility as needed)
eUnit_Integer,
eUnit_Coord,
eUnit_Percent,
eUnit_Float,
eUnit_Color, // nsCSSValue* (never null), always with an nscolor or
// an nsCSSValueFloatColor
eUnit_CurrentColor,
+ eUnit_ComplexColor, // ComplexColorValue* (never null)
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_URL, // nsCSSValue* (never null), always with a css::URLValue
eUnit_DiscreteCSSValue, // nsCSSValue* (never null)
eUnit_CSSValuePair, // nsCSSValuePair* (never null)
eUnit_CSSValueTriplet, // nsCSSValueTriplet* (never null)
@@ -349,16 +350,17 @@ private:
nsCSSValuePair* mCSSValuePair;
nsCSSValueTriplet* mCSSValueTriplet;
nsCSSRect* mCSSRect;
nsCSSValue::Array* mCSSValueArray;
nsCSSValueList* mCSSValueList;
nsCSSValueSharedList* mCSSValueSharedList;
nsCSSValuePairList* mCSSValuePairList;
nsStringBuffer* mString;
+ css::ComplexColorValue* mComplexColor;
} mValue;
public:
Unit GetUnit() const {
NS_ASSERTION(mUnit != eUnit_Null, "uninitialized");
return mUnit;
}
@@ -426,16 +428,24 @@ public:
aBuffer.Truncate();
uint32_t len = NS_strlen(GetBufferValue(mValue.mString));
mValue.mString->ToString(len, aBuffer);
}
/// @return the scale for this value, calculated with reference to @aForFrame.
gfxSize GetScaleValue(const nsIFrame* aForFrame) const;
+ const css::ComplexColorData& GetComplexColorData() const {
+ MOZ_ASSERT(mUnit == eUnit_ComplexColor, "unit mismatch");
+ return *mValue.mComplexColor;
+ }
+ StyleComplexColor GetStyleComplexColorValue() const {
+ return GetComplexColorData().ToComplexColor();
+ }
+
UniquePtr<nsCSSValueList> TakeCSSValueListValue() {
nsCSSValueList* list = GetCSSValueListValue();
mValue.mCSSValueList = nullptr;
mUnit = eUnit_Null;
return UniquePtr<nsCSSValueList>(list);
}
UniquePtr<nsCSSValuePairList> TakeCSSValuePairListValue() {
nsCSSValuePairList* list = GetCSSValuePairListValue();
@@ -482,16 +492,18 @@ public:
"aValue must be an enum that fits within mValue.mInt");
SetIntValue(static_cast<int32_t>(aInt), aUnit);
}
void SetCoordValue(nscoord aCoord);
void SetPercentValue(float aPercent);
void SetFloatValue(float aFloat);
void SetColorValue(nscolor aColor);
void SetCurrentColorValue();
+ void SetComplexColorValue(const StyleComplexColor& aColor);
+ void SetComplexColorValue(already_AddRefed<css::ComplexColorValue> aValue);
void SetUnparsedStringValue(const nsString& aString);
void SetCSSValueArrayValue(nsCSSValue::Array* aValue, Unit aUnit);
// These setters take ownership of |aValue|, and are therefore named
// "SetAndAdopt*".
void SetAndAdoptCSSValueValue(nsCSSValue *aValue, Unit aUnit);
void SetAndAdoptCSSValuePairValue(nsCSSValuePair *aValue, Unit aUnit);
void SetAndAdoptCSSValueTripletValue(nsCSSValueTriplet *aValue, Unit aUnit);
--- a/layout/style/nsCSSValue.cpp
+++ b/layout/style/nsCSSValue.cpp
@@ -156,16 +156,20 @@ nsCSSValue::nsCSSValue(const nsCSSValue&
}
else if (IsIntegerColorUnit()) {
mValue.mColor = aCopy.mValue.mColor;
}
else if (IsFloatColorUnit()) {
mValue.mFloatColor = aCopy.mValue.mFloatColor;
mValue.mFloatColor->AddRef();
}
+ else if (eCSSUnit_ComplexColor == mUnit) {
+ mValue.mComplexColor = aCopy.mValue.mComplexColor;
+ mValue.mComplexColor->AddRef();
+ }
else if (UnitHasArrayValue()) {
mValue.mArray = aCopy.mValue.mArray;
mValue.mArray->AddRef();
}
else if (eCSSUnit_URL == mUnit) {
mValue.mURL = aCopy.mValue.mURL;
mValue.mURL->AddRef();
}
@@ -266,16 +270,19 @@ bool nsCSSValue::operator==(const nsCSSV
return mValue.mInt == aOther.mValue.mInt;
}
else if (IsIntegerColorUnit()) {
return mValue.mColor == aOther.mValue.mColor;
}
else if (IsFloatColorUnit()) {
return *mValue.mFloatColor == *aOther.mValue.mFloatColor;
}
+ else if (eCSSUnit_ComplexColor == mUnit) {
+ return *mValue.mComplexColor == *aOther.mValue.mComplexColor;
+ }
else if (UnitHasArrayValue()) {
return *mValue.mArray == *aOther.mValue.mArray;
}
else if (eCSSUnit_URL == mUnit) {
return *mValue.mURL == *aOther.mValue.mURL;
}
else if (eCSSUnit_Image == mUnit) {
return *mValue.mImage == *aOther.mValue.mImage;
@@ -372,16 +379,18 @@ nscoord nsCSSValue::GetPixelLength() con
}
void nsCSSValue::DoReset()
{
if (UnitHasStringValue()) {
mValue.mString->Release();
} else if (IsFloatColorUnit()) {
mValue.mFloatColor->Release();
+ } else if (eCSSUnit_ComplexColor == mUnit) {
+ mValue.mComplexColor->Release();
} else if (UnitHasArrayValue()) {
mValue.mArray->Release();
} else if (eCSSUnit_URL == mUnit) {
mValue.mURL->Release();
} else if (eCSSUnit_Image == mUnit) {
mValue.mImage->Release();
} else if (eCSSUnit_Gradient == mUnit) {
mValue.mGradient->Release();
@@ -480,16 +489,24 @@ void nsCSSValue::SetFloatColorValue(floa
void
nsCSSValue::SetRGBAColorValue(const RGBAColorData& aValue)
{
SetFloatColorValue(aValue.mR, aValue.mG, aValue.mB,
aValue.mA, eCSSUnit_PercentageRGBAColor);
}
+void
+nsCSSValue::SetComplexColorValue(already_AddRefed<ComplexColorValue> aValue)
+{
+ Reset();
+ mUnit = eCSSUnit_ComplexColor;
+ mValue.mComplexColor = aValue.take();
+}
+
void nsCSSValue::SetArrayValue(nsCSSValue::Array* aValue, nsCSSUnit aUnit)
{
Reset();
mUnit = aUnit;
MOZ_ASSERT(UnitHasArrayValue(), "bad unit");
mValue.mArray = aValue;
mValue.mArray->AddRef();
}
@@ -1568,16 +1585,28 @@ nsCSSValue::AppendToString(nsCSSProperty
if (eCSSUnit_ShortHexColorAlpha == unit) {
aResult.AppendInt(NS_GET_A(color) / 0x11, 16);
}
} else {
MOZ_ASSERT(IsFloatColorUnit());
mValue.mFloatColor->AppendToString(unit, aResult);
}
}
+ else if (eCSSUnit_ComplexColor == unit) {
+ StyleComplexColor color = GetStyleComplexColorValue();
+ nsCSSValue serializable;
+ if (color.IsCurrentColor()) {
+ serializable.SetIntValue(NS_COLOR_CURRENTCOLOR, eCSSUnit_EnumColor);
+ } else if (color.IsNumericColor()) {
+ serializable.SetColorValue(color.mColor);
+ } else {
+ MOZ_ASSERT_UNREACHABLE("Cannot serialize a complex color");
+ }
+ serializable.AppendToString(aProperty, aResult, aSerialization);
+ }
else if (eCSSUnit_URL == unit || eCSSUnit_Image == unit) {
aResult.AppendLiteral("url(");
nsStyleUtil::AppendEscapedCSSString(
nsDependentString(GetOriginalURLValue()), aResult);
aResult.Append(')');
}
else if (eCSSUnit_Element == unit) {
aResult.AppendLiteral("-moz-element(#");
@@ -1864,16 +1893,17 @@ nsCSSValue::AppendToString(nsCSSProperty
case eCSSUnit_HexColor: break;
case eCSSUnit_ShortHexColor: break;
case eCSSUnit_HexColorAlpha: break;
case eCSSUnit_ShortHexColorAlpha: break;
case eCSSUnit_PercentageRGBColor: break;
case eCSSUnit_PercentageRGBAColor: break;
case eCSSUnit_HSLColor: break;
case eCSSUnit_HSLAColor: break;
+ case eCSSUnit_ComplexColor: break;
case eCSSUnit_Percent: aResult.Append(char16_t('%')); break;
case eCSSUnit_Number: break;
case eCSSUnit_Gradient: break;
case eCSSUnit_TokenStream: break;
case eCSSUnit_Pair: break;
case eCSSUnit_Triplet: break;
case eCSSUnit_Rect: break;
case eCSSUnit_List: break;
@@ -2051,16 +2081,21 @@ nsCSSValue::SizeOfExcludingThis(mozilla:
// Float Color
case eCSSUnit_PercentageRGBColor:
case eCSSUnit_PercentageRGBAColor:
case eCSSUnit_HSLColor:
case eCSSUnit_HSLAColor:
n += mValue.mFloatColor->SizeOfIncludingThis(aMallocSizeOf);
break;
+ // Complex Color
+ case eCSSUnit_ComplexColor:
+ n += mValue.mComplexColor->SizeOfIncludingThis(aMallocSizeOf);
+ break;
+
// Float: nothing extra to measure.
case eCSSUnit_Percent:
case eCSSUnit_Number:
case eCSSUnit_PhysicalMillimeter:
case eCSSUnit_ViewportWidth:
case eCSSUnit_ViewportHeight:
case eCSSUnit_ViewportMin:
case eCSSUnit_ViewportMax:
@@ -2779,16 +2814,27 @@ css::ImageValue::~ImageValue()
if (proxy) {
proxy->CancelAndForgetObserver(NS_BINDING_ABORTED);
}
iter.Remove();
}
}
+size_t
+css::ComplexColorValue::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
+{
+ // Only measure it if it's unshared, to avoid double-counting.
+ size_t n = 0;
+ if (mRefCnt <= 1) {
+ n += aMallocSizeOf(this);
+ }
+ return n;
+}
+
nsCSSValueGradientStop::nsCSSValueGradientStop()
: mLocation(eCSSUnit_None),
mColor(eCSSUnit_Null),
mIsInterpolationHint(false)
{
MOZ_COUNT_CTOR(nsCSSValueGradientStop);
}
--- a/layout/style/nsCSSValue.h
+++ b/layout/style/nsCSSValue.h
@@ -8,16 +8,17 @@
#ifndef nsCSSValue_h___
#define nsCSSValue_h___
#include <type_traits>
#include "mozilla/Attributes.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/SheetType.h"
+#include "mozilla/StyleComplexColor.h"
#include "mozilla/UniquePtr.h"
#include "nsIPrincipal.h"
#include "nsIURI.h"
#include "nsCOMPtr.h"
#include "nsCSSKeywords.h"
#include "nsCSSPropertyID.h"
#include "nsCSSProps.h"
@@ -340,16 +341,66 @@ struct RGBAColorData
RGBAColorData WithAlpha(float aAlpha) const
{
RGBAColorData result = *this;
result.mA = aAlpha;
return result;
}
};
+struct ComplexColorData
+{
+ RGBAColorData mColor;
+ float mForegroundRatio;
+
+ ComplexColorData() = default;
+ ComplexColorData(const RGBAColorData& aColor, float aForegroundRatio)
+ : mColor(aColor), mForegroundRatio(aForegroundRatio) {}
+ ComplexColorData(nscolor aColor, float aForegroundRatio)
+ : mColor(aColor), mForegroundRatio(aForegroundRatio) {}
+ explicit ComplexColorData(const StyleComplexColor& aColor)
+ : mColor(aColor.mColor)
+ , mForegroundRatio(aColor.mForegroundRatio * (1.0f / 255.0f)) {}
+
+ bool operator==(const ComplexColorData& aOther) const
+ {
+ return mForegroundRatio == aOther.mForegroundRatio &&
+ (IsCurrentColor() || mColor == aOther.mColor);
+ }
+ bool operator!=(const ComplexColorData& aOther) const
+ {
+ return !(*this == aOther);
+ }
+
+ bool IsCurrentColor() const { return mForegroundRatio >= 1.0f; }
+ bool IsNumericColor() const { return mForegroundRatio <= 0.0f; }
+
+ StyleComplexColor ToComplexColor() const
+ {
+ return StyleComplexColor(
+ mColor.ToColor(), ClampColor(mForegroundRatio * 255.0f));
+ }
+};
+
+struct ComplexColorValue final : public ComplexColorData
+{
+ // Just redirect any parameter to the data struct.
+ template<typename... Args>
+ explicit ComplexColorValue(Args&&... aArgs)
+ : ComplexColorData(Forward<Args>(aArgs)...) {}
+ ComplexColorValue(const ComplexColorValue&) = delete;
+
+ NS_INLINE_DECL_REFCOUNTING(ComplexColorValue)
+
+ size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
+
+private:
+ ~ComplexColorValue() {}
+};
+
} // namespace css
} // namespace mozilla
enum nsCSSUnit {
eCSSUnit_Null = 0, // (n/a) null unit, value is not specified
eCSSUnit_Auto = 1, // (n/a) value is algorithmic
eCSSUnit_Inherit = 2, // (n/a) value is inherited
eCSSUnit_Initial = 3, // (n/a) value is default UA value
@@ -434,16 +485,17 @@ enum nsCSSUnit {
// percentage components. Values over
// 100% are allowed.
eCSSUnit_PercentageRGBAColor = 88, // (nsCSSValueFloatColor*) an RGBA value
// specified as rgba() with percentage
// components. Values over 100% are
// allowed.
eCSSUnit_HSLColor = 89, // (nsCSSValueFloatColor*)
eCSSUnit_HSLAColor = 90, // (nsCSSValueFloatColor*)
+ eCSSUnit_ComplexColor = 91, // (ComplexColorValue*)
eCSSUnit_Percent = 100, // (float) 1.0 == 100%) value is percentage of something
eCSSUnit_Number = 101, // (float) value is numeric (usually multiplier, different behavior than percent)
// Physical length units
eCSSUnit_PhysicalMillimeter = 200, // (float) 1/25.4 inch
// Length units - relative
@@ -682,16 +734,21 @@ public:
const char16_t* GetStringBufferValue() const
{
MOZ_ASSERT(UnitHasStringValue(), "not a string value");
return GetBufferValue(mValue.mString);
}
nscolor GetColorValue() const;
bool IsNonTransparentColor() const;
+ mozilla::StyleComplexColor GetStyleComplexColorValue() const
+ {
+ MOZ_ASSERT(mUnit == eCSSUnit_ComplexColor);
+ return mValue.mComplexColor->ToComplexColor();
+ }
Array* GetArrayValue() const
{
MOZ_ASSERT(UnitHasArrayValue(), "not an array value");
return mValue.mArray;
}
nsIURI* GetURLValue() const
@@ -813,16 +870,18 @@ public:
void SetStringValue(const nsString& aValue, nsCSSUnit aUnit);
void SetColorValue(nscolor aValue);
void SetIntegerColorValue(nscolor aValue, nsCSSUnit aUnit);
void SetFloatColorValue(float aComponent1,
float aComponent2,
float aComponent3,
float aAlpha, nsCSSUnit aUnit);
void SetRGBAColorValue(const mozilla::css::RGBAColorData& aValue);
+ void SetComplexColorValue(
+ already_AddRefed<mozilla::css::ComplexColorValue> aValue);
void SetArrayValue(nsCSSValue::Array* aArray, nsCSSUnit aUnit);
void SetURLValue(mozilla::css::URLValue* aURI);
void SetImageValue(mozilla::css::ImageValue* aImage);
void SetGradientValue(nsCSSValueGradient* aGradient);
void SetTokenStreamValue(nsCSSValueTokenStream* aTokenStream);
void SetGridTemplateAreas(mozilla::css::GridTemplateAreasValue* aValue);
void SetFontFamilyListValue(mozilla::css::FontFamilyListRefCnt* aFontListValue);
void SetPairValue(const nsCSSValuePair* aPair);
@@ -920,16 +979,17 @@ protected:
nsCSSValueTriplet_heap* MOZ_OWNING_REF mTriplet;
nsCSSValueList_heap* MOZ_OWNING_REF mList;
nsCSSValueList* mListDependent;
nsCSSValueSharedList* MOZ_OWNING_REF mSharedList;
nsCSSValuePairList_heap* MOZ_OWNING_REF mPairList;
nsCSSValuePairList* mPairListDependent;
nsCSSValueFloatColor* MOZ_OWNING_REF mFloatColor;
mozilla::css::FontFamilyListRefCnt* MOZ_OWNING_REF mFontFamilyList;
+ mozilla::css::ComplexColorValue* MOZ_OWNING_REF mComplexColor;
} mValue;
};
struct nsCSSValue::Array final {
// return |Array| with reference count of zero
static Array* Create(size_t aItemCount) {
return new (aItemCount) Array(aItemCount);