--- a/dom/smil/nsSMILCSSValueType.cpp
+++ b/dom/smil/nsSMILCSSValueType.cpp
@@ -28,40 +28,67 @@
using namespace mozilla::dom;
using mozilla::StyleAnimationValue;
/*static*/ nsSMILCSSValueType nsSMILCSSValueType::sSingleton;
struct ValueWrapper {
ValueWrapper(nsCSSPropertyID aPropID, const AnimationValue& aValue)
- : mPropID(aPropID), mCSSValue(aValue) {}
+ : mPropID(aPropID)
+ {
+ if (aValue.mServo) {
+ mServoValue = aValue.mServo;
+ return;
+ }
+ mGeckoValue = aValue.mGecko;
+ }
ValueWrapper(nsCSSPropertyID aPropID, const StyleAnimationValue& aValue)
- : mPropID(aPropID), mCSSValue(aValue) {}
+ : mPropID(aPropID), mGeckoValue(aValue) {}
ValueWrapper(nsCSSPropertyID aPropID,
const RefPtr<RawServoAnimationValue>& aValue)
- : mPropID(aPropID), mCSSValue(aValue) {}
+ : mPropID(aPropID), mServoValue(aValue) {}
+
+ bool operator==(const ValueWrapper& aOther) const
+ {
+ if (mPropID != aOther.mPropID) {
+ return false;
+ }
+
+ if (mServoValue && aOther.mServoValue) {
+ return Servo_AnimationValue_DeepEqual(mServoValue, aOther.mServoValue);
+ }
+ return !mServoValue && !aOther.mServoValue &&
+ mGeckoValue == aOther.mGeckoValue;
+ }
+
+ bool operator!=(const ValueWrapper& aOther) const
+ {
+ return !(*this == aOther);
+ }
nsCSSPropertyID mPropID;
- AnimationValue mCSSValue;
+ RefPtr<RawServoAnimationValue> mServoValue;
+ StyleAnimationValue mGeckoValue;
+
};
// Helper Methods
// --------------
-static const AnimationValue*
+static const StyleAnimationValue*
GetZeroValueForUnit(StyleAnimationValue::Unit aUnit)
{
- static const AnimationValue sZeroCoord(
- StyleAnimationValue(0, StyleAnimationValue::CoordConstructor));
- static const AnimationValue sZeroPercent(
- StyleAnimationValue(0.0f, StyleAnimationValue::PercentConstructor));
- static const AnimationValue sZeroFloat(
- StyleAnimationValue(0.0f, StyleAnimationValue::FloatConstructor));
- static const AnimationValue sZeroColor(
- StyleAnimationValue(NS_RGB(0,0,0), StyleAnimationValue::ColorConstructor));
+ static const StyleAnimationValue
+ sZeroCoord(0, StyleAnimationValue::CoordConstructor);
+ static const StyleAnimationValue
+ sZeroPercent(0.0f, StyleAnimationValue::PercentConstructor);
+ static const StyleAnimationValue
+ sZeroFloat(0.0f, StyleAnimationValue::FloatConstructor);
+ static const StyleAnimationValue
+ sZeroColor(NS_RGB(0,0,0), StyleAnimationValue::ColorConstructor);
MOZ_ASSERT(aUnit != StyleAnimationValue::eUnit_Null,
"Need non-null unit for a zero value");
switch (aUnit) {
case StyleAnimationValue::eUnit_Coord:
return &sZeroCoord;
case StyleAnimationValue::eUnit_Percent:
return &sZeroPercent;
@@ -74,76 +101,70 @@ GetZeroValueForUnit(StyleAnimationValue:
}
}
// This method requires at least one of its arguments to be non-null.
//
// If one argument is null, this method updates it to point to "zero"
// for the other argument's Unit (if applicable; otherwise, we return false).
//
-// If neither argument is null, this method generally does nothing, though it
-// may apply a workaround for the special case where a 0 length-value is mixed
-// with a eUnit_Float value. (See comment below.)
+// If neither argument is null, this method does nothing.
//
-// |aZeroValueStorage| should be a null AnimationValue. This is used for the
-// Servo backend where we may need to allocate a new ServoAnimationValue to
+// |aZeroValueStorage| should be a reference to a RefPtr<RawServoAnimationValue>.
+// This is used where we may need to allocate a new ServoAnimationValue to
// represent the appropriate zero value.
//
-// Returns true on success, or false.
+// Returns true on success, or otherwise.
static bool
-FinalizeStyleAnimationValues(const AnimationValue*& aValue1,
- const AnimationValue*& aValue2,
- AnimationValue& aZeroValueStorage)
+FinalizeServoAnimationValues(const RefPtr<RawServoAnimationValue>*& aValue1,
+ const RefPtr<RawServoAnimationValue>*& aValue2,
+ RefPtr<RawServoAnimationValue>& aZeroValueStorage)
+{
+ MOZ_ASSERT(aValue1 || aValue2, "expecting at least one non-null value");
+
+ // Are we missing either val? (If so, it's an implied 0 in other val's units)
+
+ if (!aValue1) {
+ aZeroValueStorage = Servo_AnimationValues_GetZeroValue(*aValue2).Consume();
+ aValue1 = &aZeroValueStorage;
+ } else if (!aValue2) {
+ aZeroValueStorage = Servo_AnimationValues_GetZeroValue(*aValue1).Consume();
+ aValue2 = &aZeroValueStorage;
+ }
+ return *aValue1 && *aValue2;
+}
+
+static bool
+FinalizeStyleAnimationValues(const StyleAnimationValue*& aValue1,
+ const StyleAnimationValue*& aValue2)
{
MOZ_ASSERT(aValue1 || aValue2,
"expecting at least one non-null value");
- MOZ_ASSERT(!aValue1 || !aValue2 || !aValue1->mServo == !aValue2->mServo,
- "If both values are specified, they should be for the same"
- " style system");
- MOZ_ASSERT(aZeroValueStorage.IsNull(),
- "Zero storage should be empty");
-
- bool isServo = aValue1 ? aValue1->mServo : aValue2->mServo;
-
- // Are we missing either val? (If so, it's an implied 0 in other val's units)
-
- if (isServo) {
- if (!aValue1) {
- aZeroValueStorage.mServo =
- Servo_AnimationValues_GetZeroValue(aValue2->mServo).Consume();
- aValue1 = &aZeroValueStorage;
- } else if (!aValue2) {
- aZeroValueStorage.mServo =
- Servo_AnimationValues_GetZeroValue(aValue1->mServo).Consume();
- aValue2 = &aZeroValueStorage;
- }
- return aValue1->mServo && aValue2->mServo;
- }
if (!aValue1) {
- aValue1 = GetZeroValueForUnit(aValue2->mGecko.GetUnit());
+ aValue1 = GetZeroValueForUnit(aValue2->GetUnit());
return !!aValue1; // Fail if we have no zero value for this unit.
}
if (!aValue2) {
- aValue2 = GetZeroValueForUnit(aValue1->mGecko.GetUnit());
+ aValue2 = GetZeroValueForUnit(aValue1->GetUnit());
return !!aValue2; // Fail if we have no zero value for this unit.
}
// Ok, both values were specified.
// Need to handle a special-case, though: unitless nonzero length (parsed as
// eUnit_Float) mixed with unitless 0 length (parsed as eUnit_Coord). These
// won't interoperate in StyleAnimationValue, since their Units don't match.
// In this case, we replace the eUnit_Coord 0 value with eUnit_Float 0 value.
- const AnimationValue& zeroCoord =
+ const StyleAnimationValue& zeroCoord =
*GetZeroValueForUnit(StyleAnimationValue::eUnit_Coord);
if (*aValue1 == zeroCoord &&
- aValue2->mGecko.GetUnit() == StyleAnimationValue::eUnit_Float) {
+ aValue2->GetUnit() == StyleAnimationValue::eUnit_Float) {
aValue1 = GetZeroValueForUnit(StyleAnimationValue::eUnit_Float);
} else if (*aValue2 == zeroCoord &&
- aValue1->mGecko.GetUnit() == StyleAnimationValue::eUnit_Float) {
+ aValue1->GetUnit() == StyleAnimationValue::eUnit_Float) {
aValue2 = GetZeroValueForUnit(StyleAnimationValue::eUnit_Float);
}
return true;
}
static void
InvertSign(StyleAnimationValue& aValue)
@@ -229,31 +250,77 @@ nsSMILCSSValueType::IsEqual(const nsSMIL
const ValueWrapper* leftWrapper = ExtractValueWrapper(aLeft);
const ValueWrapper* rightWrapper = ExtractValueWrapper(aRight);
if (leftWrapper) {
if (rightWrapper) {
// Both non-null
NS_WARNING_ASSERTION(leftWrapper != rightWrapper,
"Two nsSMILValues with matching ValueWrapper ptr");
- return (leftWrapper->mPropID == rightWrapper->mPropID &&
- leftWrapper->mCSSValue == rightWrapper->mCSSValue);
+ return *leftWrapper == *rightWrapper;
}
// Left non-null, right null
return false;
}
if (rightWrapper) {
// Left null, right non-null
return false;
}
// Both null
return true;
}
static bool
+AddOrAccumulateForServo(nsSMILValue& aDest,
+ const ValueWrapper* aValueToAddWrapper,
+ ValueWrapper* aDestWrapper,
+ CompositeOperation aCompositeOp,
+ uint64_t aCount)
+{
+ nsCSSPropertyID property = aValueToAddWrapper
+ ? aValueToAddWrapper->mPropID
+ : aDestWrapper->mPropID;
+ const RefPtr<RawServoAnimationValue>* valueToAdd =
+ aValueToAddWrapper
+ ? &aValueToAddWrapper->mServoValue
+ : nullptr;
+ const RefPtr<RawServoAnimationValue>* destValue =
+ aDestWrapper
+ ? &aDestWrapper->mServoValue
+ : nullptr;
+ RefPtr<RawServoAnimationValue> zeroValueStorage;
+ if (!FinalizeServoAnimationValues(valueToAdd, destValue, zeroValueStorage)) {
+ return false;
+ }
+
+ // FinalizeServoAnimationValues may have updated destValue so we should make
+ // sure the aDest and aDestWrapper outparams are up-to-date.
+ if (aDestWrapper) {
+ aDestWrapper->mServoValue = *destValue;
+ } else {
+ // aDest may be a barely-initialized "zero" destination.
+ aDest.mU.mPtr = aDestWrapper = new ValueWrapper(property, *destValue);
+ }
+
+ RefPtr<RawServoAnimationValue> result;
+ if (aCompositeOp == CompositeOperation::Add) {
+ result = Servo_AnimationValues_Add(*destValue, *valueToAdd).Consume();
+ } else {
+ result = Servo_AnimationValues_Accumulate(*destValue,
+ *valueToAdd,
+ aCount).Consume();
+ }
+
+ if (result) {
+ aDestWrapper->mServoValue = result;
+ }
+ return result;
+}
+
+static bool
AddOrAccumulate(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
CompositeOperation aCompositeOp, uint64_t aCount)
{
MOZ_ASSERT(aValueToAdd.mType == aDest.mType,
"Trying to add mismatching types");
MOZ_ASSERT(aValueToAdd.mType == &nsSMILCSSValueType::sSingleton,
"Unexpected SMIL value type");
MOZ_ASSERT(aCompositeOp == CompositeOperation::Add ||
@@ -272,62 +339,53 @@ AddOrAccumulate(nsSMILValue& aDest, cons
: destWrapper->mPropID;
// Special case: font-size-adjust and stroke-dasharray are explicitly
// non-additive (even though StyleAnimationValue *could* support adding them)
if (property == eCSSProperty_font_size_adjust ||
property == eCSSProperty_stroke_dasharray) {
return false;
}
- const AnimationValue* valueToAdd = valueToAddWrapper
- ? &valueToAddWrapper->mCSSValue
- : nullptr;
- const AnimationValue* destValue = destWrapper
- ? &destWrapper->mCSSValue
- : nullptr;
- AnimationValue zeroValueStorage;
- if (!FinalizeStyleAnimationValues(valueToAdd, destValue,
- zeroValueStorage)) {
+ bool isServo = valueToAddWrapper
+ ? valueToAddWrapper->mServoValue
+ : destWrapper->mServoValue;
+ if (isServo) {
+ return AddOrAccumulateForServo(aDest,
+ valueToAddWrapper,
+ destWrapper,
+ aCompositeOp,
+ aCount);
+ }
+
+ const StyleAnimationValue* valueToAdd = valueToAddWrapper ?
+ &valueToAddWrapper->mGeckoValue : nullptr;
+ const StyleAnimationValue* destValue = destWrapper ?
+ &destWrapper->mGeckoValue : nullptr;
+ if (!FinalizeStyleAnimationValues(valueToAdd, destValue)) {
return false;
}
// Did FinalizeStyleAnimationValues change destValue?
// If so, update outparam to use the new value.
- if (destWrapper && &destWrapper->mCSSValue != destValue) {
- destWrapper->mCSSValue = *destValue;
+ if (destWrapper && &destWrapper->mGeckoValue != destValue) {
+ destWrapper->mGeckoValue = *destValue;
}
// Handle barely-initialized "zero" destination.
if (!destWrapper) {
aDest.mU.mPtr = destWrapper = new ValueWrapper(property, *destValue);
}
- if (destWrapper->mCSSValue.mServo) {
- RefPtr<RawServoAnimationValue> result;
- if (aCompositeOp == CompositeOperation::Add) {
- result = Servo_AnimationValues_Add(destWrapper->mCSSValue.mServo,
- valueToAdd->mServo).Consume();
- } else {
- result = Servo_AnimationValues_Accumulate(destWrapper->mCSSValue.mServo,
- valueToAdd->mServo,
- aCount).Consume();
- }
-
- if (result) {
- destWrapper->mCSSValue.mServo = result;
- }
- return result;
- }
-
// For Gecko, we currently call Add for either composite mode.
//
// This is not ideal, but it doesn't make any difference for the set of
// properties we currently allow adding in SMIL and this code path will
// hopefully become obsolete before we expand that set.
- return StyleAnimationValue::Add(property, destWrapper->mCSSValue.mGecko,
- valueToAdd->mGecko, aCount);
+ return StyleAnimationValue::Add(property,
+ destWrapper->mGeckoValue,
+ valueToAddWrapper->mGeckoValue, aCount);
}
nsresult
nsSMILCSSValueType::SandwichAdd(nsSMILValue& aDest,
const nsSMILValue& aValueToAdd) const
{
return AddOrAccumulate(aDest, aValueToAdd, CompositeOperation::Add, 1)
? NS_OK
@@ -339,54 +397,120 @@ nsSMILCSSValueType::Add(nsSMILValue& aDe
uint32_t aCount) const
{
return AddOrAccumulate(aDest, aValueToAdd, CompositeOperation::Accumulate,
aCount)
? NS_OK
: NS_ERROR_FAILURE;
}
+static nsresult
+ComputeDistanceForServo(const ValueWrapper* aFromWrapper,
+ const ValueWrapper& aToWrapper,
+ double& aDistance)
+{
+ const RefPtr<RawServoAnimationValue>* fromValue =
+ aFromWrapper ? &aFromWrapper->mServoValue : nullptr;
+ const RefPtr<RawServoAnimationValue>* toValue = &aToWrapper.mServoValue;
+ RefPtr<RawServoAnimationValue> zeroValueStorage;
+ if (!FinalizeServoAnimationValues(fromValue, toValue, zeroValueStorage)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ aDistance = Servo_AnimationValues_ComputeDistance(*fromValue, *toValue);
+
+ return NS_OK;
+}
+
nsresult
nsSMILCSSValueType::ComputeDistance(const nsSMILValue& aFrom,
const nsSMILValue& aTo,
double& aDistance) const
{
MOZ_ASSERT(aFrom.mType == aTo.mType,
"Trying to compare different types");
MOZ_ASSERT(aFrom.mType == this, "Unexpected source type");
const ValueWrapper* fromWrapper = ExtractValueWrapper(aFrom);
const ValueWrapper* toWrapper = ExtractValueWrapper(aTo);
MOZ_ASSERT(toWrapper, "expecting non-null endpoint");
- const AnimationValue* fromCSSValue = fromWrapper
- ? &fromWrapper->mCSSValue
- : nullptr;
- const AnimationValue* toCSSValue = &toWrapper->mCSSValue;
- AnimationValue zeroValueStorage;
- if (!FinalizeStyleAnimationValues(fromCSSValue, toCSSValue,
- zeroValueStorage)) {
+ if (toWrapper->mServoValue) {
+ return ComputeDistanceForServo(fromWrapper, *toWrapper, aDistance);
+ }
+
+ const StyleAnimationValue* fromCSSValue = fromWrapper ?
+ &fromWrapper->mGeckoValue : nullptr;
+ const StyleAnimationValue* toCSSValue = &toWrapper->mGeckoValue;
+ if (!FinalizeStyleAnimationValues(fromCSSValue, toCSSValue)) {
return NS_ERROR_FAILURE;
}
- if (toCSSValue->mServo) {
- aDistance = Servo_AnimationValues_ComputeDistance(fromCSSValue->mServo,
- toCSSValue->mServo);
- return NS_OK;
- }
-
return StyleAnimationValue::ComputeDistance(toWrapper->mPropID,
- fromCSSValue->mGecko,
- toCSSValue->mGecko,
+ fromWrapper->mGeckoValue,
+ toWrapper->mGeckoValue,
nullptr,
aDistance)
? NS_OK
: NS_ERROR_FAILURE;
}
+static nsresult
+InterpolateForGecko(const ValueWrapper* aStartWrapper,
+ const ValueWrapper& aEndWrapper,
+ double aUnitDistance,
+ nsSMILValue& aResult)
+{
+ const StyleAnimationValue* startCSSValue = aStartWrapper
+ ? &aStartWrapper->mGeckoValue
+ : nullptr;
+ const StyleAnimationValue* endCSSValue = &aEndWrapper.mGeckoValue;
+ if (!FinalizeStyleAnimationValues(startCSSValue, endCSSValue)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ StyleAnimationValue resultValue;
+ if (StyleAnimationValue::Interpolate(aEndWrapper.mPropID,
+ *startCSSValue,
+ *endCSSValue,
+ aUnitDistance, resultValue)) {
+ aResult.mU.mPtr = new ValueWrapper(aEndWrapper.mPropID, resultValue);
+ return NS_OK;
+ }
+ return NS_ERROR_FAILURE;
+}
+
+static nsresult
+InterpolateForServo(const ValueWrapper* aStartWrapper,
+ const ValueWrapper& aEndWrapper,
+ double aUnitDistance,
+ nsSMILValue& aResult)
+{
+ const RefPtr<RawServoAnimationValue>*
+ startValue = aStartWrapper
+ ? &aStartWrapper->mServoValue
+ : nullptr;
+ const RefPtr<RawServoAnimationValue>* endValue = &aEndWrapper.mServoValue;
+ RefPtr<RawServoAnimationValue> zeroValueStorage;
+ if (!FinalizeServoAnimationValues(startValue, endValue, zeroValueStorage)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ RefPtr<RawServoAnimationValue> result =
+ Servo_AnimationValues_Interpolate(*startValue,
+ *endValue,
+ aUnitDistance).Consume();
+ if (!result) {
+ return NS_ERROR_FAILURE;
+ }
+ aResult.mU.mPtr = new ValueWrapper(aEndWrapper.mPropID, Move(result));
+
+ return NS_OK;
+}
+
nsresult
nsSMILCSSValueType::Interpolate(const nsSMILValue& aStartVal,
const nsSMILValue& aEndVal,
double aUnitDistance,
nsSMILValue& aResult) const
{
MOZ_ASSERT(aStartVal.mType == aEndVal.mType,
"Trying to interpolate different types");
@@ -396,51 +520,27 @@ nsSMILCSSValueType::Interpolate(const ns
MOZ_ASSERT(aUnitDistance >= 0.0 && aUnitDistance <= 1.0,
"unit distance value out of bounds");
MOZ_ASSERT(!aResult.mU.mPtr, "expecting barely-initialized outparam");
const ValueWrapper* startWrapper = ExtractValueWrapper(aStartVal);
const ValueWrapper* endWrapper = ExtractValueWrapper(aEndVal);
MOZ_ASSERT(endWrapper, "expecting non-null endpoint");
- const AnimationValue* startCSSValue = startWrapper
- ? &startWrapper->mCSSValue
- : nullptr;
- const AnimationValue* endCSSValue = &endWrapper->mCSSValue;
- AnimationValue zeroValueStorage;
- if (!FinalizeStyleAnimationValues(startCSSValue, endCSSValue,
- zeroValueStorage)) {
- return NS_ERROR_FAILURE;
+ if (endWrapper->mServoValue) {
+ return InterpolateForServo(startWrapper,
+ *endWrapper,
+ aUnitDistance,
+ aResult);
}
- MOZ_ASSERT(!startCSSValue ||
- !startCSSValue->mServo == !endCSSValue->mServo,
- "Start and end values should use the same style system");
-
- if (endCSSValue->mServo) {
- RefPtr<RawServoAnimationValue> resultValue =
- Servo_AnimationValues_Interpolate(startCSSValue->mServo,
- endCSSValue->mServo,
- aUnitDistance).Consume();
- if (!resultValue) {
- return NS_ERROR_FAILURE;
- }
- aResult.mU.mPtr = new ValueWrapper(endWrapper->mPropID, resultValue);
- return NS_OK;
- }
-
- StyleAnimationValue resultValue;
- if (StyleAnimationValue::Interpolate(endWrapper->mPropID,
- startCSSValue->mGecko,
- endCSSValue->mGecko,
- aUnitDistance, resultValue)) {
- aResult.mU.mPtr = new ValueWrapper(endWrapper->mPropID, resultValue);
- return NS_OK;
- }
- return NS_ERROR_FAILURE;
+ return InterpolateForGecko(startWrapper,
+ *endWrapper,
+ aUnitDistance,
+ aResult);
}
// Helper function to extract presContext
static nsPresContext*
GetPresContextForElement(Element* aElem)
{
nsIDocument* doc = aElem->GetUncomposedDoc();
if (!doc) {
@@ -676,17 +776,27 @@ nsSMILCSSValueType::ValueToString(const
{
MOZ_ASSERT(aValue.mType == &nsSMILCSSValueType::sSingleton,
"Unexpected SMIL value type");
const ValueWrapper* wrapper = ExtractValueWrapper(aValue);
if (!wrapper) {
return;
}
- wrapper->mCSSValue.SerializeSpecifiedValue(wrapper->mPropID, aString);
+ if (wrapper->mServoValue) {
+ Servo_AnimationValue_Serialize(wrapper->mServoValue,
+ wrapper->mPropID,
+ &aString);
+ return;
+ }
+
+ DebugOnly<bool> uncomputeResult =
+ StyleAnimationValue::UncomputeValue(wrapper->mPropID,
+ wrapper->mGeckoValue,
+ aString);
}
// static
nsCSSPropertyID
nsSMILCSSValueType::PropertyFromValue(const nsSMILValue& aValue)
{
if (aValue.mType != &nsSMILCSSValueType::sSingleton) {
return eCSSProperty_UNKNOWN;