summaryrefslogtreecommitdiffstats
path: root/dom/smil/SMILCSSValueType.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /dom/smil/SMILCSSValueType.cpp
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/smil/SMILCSSValueType.cpp')
-rw-r--r--dom/smil/SMILCSSValueType.cpp571
1 files changed, 571 insertions, 0 deletions
diff --git a/dom/smil/SMILCSSValueType.cpp b/dom/smil/SMILCSSValueType.cpp
new file mode 100644
index 0000000000..a93aeffffa
--- /dev/null
+++ b/dom/smil/SMILCSSValueType.cpp
@@ -0,0 +1,571 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* representation of a value for a SMIL-animated CSS property */
+
+#include "SMILCSSValueType.h"
+
+#include "nsComputedDOMStyle.h"
+#include "nsColor.h"
+#include "nsCSSProps.h"
+#include "nsCSSValue.h"
+#include "nsDebug.h"
+#include "nsPresContextInlines.h"
+#include "nsPresContext.h"
+#include "nsString.h"
+#include "nsStyleUtil.h"
+#include "mozilla/DeclarationBlock.h"
+#include "mozilla/PresShell.h"
+#include "mozilla/PresShellInlines.h"
+#include "mozilla/ServoBindings.h"
+#include "mozilla/StyleAnimationValue.h"
+#include "mozilla/ServoCSSParser.h"
+#include "mozilla/ServoStyleSet.h"
+#include "mozilla/SMILParserUtils.h"
+#include "mozilla/SMILValue.h"
+#include "mozilla/dom/BaseKeyframeTypesBinding.h"
+#include "mozilla/dom/Document.h"
+#include "mozilla/dom/Element.h"
+
+using namespace mozilla::dom;
+
+namespace mozilla {
+
+using ServoAnimationValues = CopyableAutoTArray<RefPtr<StyleAnimationValue>, 1>;
+
+/*static*/
+SMILCSSValueType SMILCSSValueType::sSingleton;
+
+struct ValueWrapper {
+ ValueWrapper(nsCSSPropertyID aPropID, const AnimationValue& aValue)
+ : mPropID(aPropID) {
+ MOZ_ASSERT(!aValue.IsNull());
+ mServoValues.AppendElement(aValue.mServo);
+ }
+ ValueWrapper(nsCSSPropertyID aPropID,
+ const RefPtr<StyleAnimationValue>& aValue)
+ : mPropID(aPropID), mServoValues{(aValue)} {}
+ ValueWrapper(nsCSSPropertyID aPropID, ServoAnimationValues&& aValues)
+ : mPropID(aPropID), mServoValues{std::move(aValues)} {}
+
+ bool operator==(const ValueWrapper& aOther) const {
+ if (mPropID != aOther.mPropID) {
+ return false;
+ }
+
+ MOZ_ASSERT(!mServoValues.IsEmpty());
+ size_t len = mServoValues.Length();
+ if (len != aOther.mServoValues.Length()) {
+ return false;
+ }
+ for (size_t i = 0; i < len; i++) {
+ if (!Servo_AnimationValue_DeepEqual(mServoValues[i],
+ aOther.mServoValues[i])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool operator!=(const ValueWrapper& aOther) const {
+ return !(*this == aOther);
+ }
+
+ nsCSSPropertyID mPropID;
+ ServoAnimationValues mServoValues;
+};
+
+// Helper Methods
+// --------------
+
+// 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 simply returns true.
+//
+// If both arguments are null, this method returns false.
+//
+// |aZeroValueStorage| should be a reference to a
+// RefPtr<StyleAnimationValue>. This is used where we may need to allocate a
+// new ServoAnimationValue to represent the appropriate zero value.
+//
+// Returns true on success, or otherwise.
+static bool FinalizeServoAnimationValues(
+ const RefPtr<StyleAnimationValue>*& aValue1,
+ const RefPtr<StyleAnimationValue>*& aValue2,
+ RefPtr<StyleAnimationValue>& aZeroValueStorage) {
+ if (!aValue1 && !aValue2) {
+ return false;
+ }
+
+ // 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 ValueWrapper* ExtractValueWrapper(SMILValue& aValue) {
+ return static_cast<ValueWrapper*>(aValue.mU.mPtr);
+}
+
+static const ValueWrapper* ExtractValueWrapper(const SMILValue& aValue) {
+ return static_cast<const ValueWrapper*>(aValue.mU.mPtr);
+}
+
+// Class methods
+// -------------
+void SMILCSSValueType::Init(SMILValue& aValue) const {
+ MOZ_ASSERT(aValue.IsNull(), "Unexpected SMIL value type");
+
+ aValue.mU.mPtr = nullptr;
+ aValue.mType = this;
+}
+
+void SMILCSSValueType::Destroy(SMILValue& aValue) const {
+ MOZ_ASSERT(aValue.mType == this, "Unexpected SMIL value type");
+ delete static_cast<ValueWrapper*>(aValue.mU.mPtr);
+ aValue.mType = SMILNullType::Singleton();
+}
+
+nsresult SMILCSSValueType::Assign(SMILValue& aDest,
+ const SMILValue& aSrc) const {
+ MOZ_ASSERT(aDest.mType == aSrc.mType, "Incompatible SMIL types");
+ MOZ_ASSERT(aDest.mType == this, "Unexpected SMIL value type");
+ const ValueWrapper* srcWrapper = ExtractValueWrapper(aSrc);
+ ValueWrapper* destWrapper = ExtractValueWrapper(aDest);
+
+ if (srcWrapper) {
+ if (!destWrapper) {
+ // barely-initialized dest -- need to alloc & copy
+ aDest.mU.mPtr = new ValueWrapper(*srcWrapper);
+ } else {
+ // both already fully-initialized -- just copy straight across
+ *destWrapper = *srcWrapper;
+ }
+ } else if (destWrapper) {
+ // fully-initialized dest, barely-initialized src -- clear dest
+ delete destWrapper;
+ aDest.mU.mPtr = destWrapper = nullptr;
+ } // else, both are barely-initialized -- nothing to do.
+
+ return NS_OK;
+}
+
+bool SMILCSSValueType::IsEqual(const SMILValue& aLeft,
+ const SMILValue& aRight) const {
+ MOZ_ASSERT(aLeft.mType == aRight.mType, "Incompatible SMIL types");
+ MOZ_ASSERT(aLeft.mType == this, "Unexpected SMIL value");
+ const ValueWrapper* leftWrapper = ExtractValueWrapper(aLeft);
+ const ValueWrapper* rightWrapper = ExtractValueWrapper(aRight);
+
+ if (leftWrapper) {
+ if (rightWrapper) {
+ // Both non-null
+ NS_WARNING_ASSERTION(leftWrapper != rightWrapper,
+ "Two SMILValues with matching ValueWrapper ptr");
+ 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(SMILValue& aDest,
+ const ValueWrapper* aValueToAddWrapper,
+ ValueWrapper* aDestWrapper,
+ CompositeOperation aCompositeOp,
+ uint64_t aCount) {
+ nsCSSPropertyID property =
+ aValueToAddWrapper ? aValueToAddWrapper->mPropID : aDestWrapper->mPropID;
+ size_t len = aValueToAddWrapper ? aValueToAddWrapper->mServoValues.Length()
+ : aDestWrapper->mServoValues.Length();
+
+ MOZ_ASSERT(!aValueToAddWrapper || !aDestWrapper ||
+ aValueToAddWrapper->mServoValues.Length() ==
+ aDestWrapper->mServoValues.Length(),
+ "Both of values' length in the wrappers should be the same if "
+ "both of them exist");
+
+ for (size_t i = 0; i < len; i++) {
+ const RefPtr<StyleAnimationValue>* valueToAdd =
+ aValueToAddWrapper ? &aValueToAddWrapper->mServoValues[i] : nullptr;
+ const RefPtr<StyleAnimationValue>* destValue =
+ aDestWrapper ? &aDestWrapper->mServoValues[i] : nullptr;
+ RefPtr<StyleAnimationValue> 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->mServoValues[i] = *destValue;
+ } else {
+ // aDest may be a barely-initialized "zero" destination.
+ aDest.mU.mPtr = aDestWrapper = new ValueWrapper(property, *destValue);
+ aDestWrapper->mServoValues.SetLength(len);
+ }
+
+ RefPtr<StyleAnimationValue> result;
+ if (aCompositeOp == CompositeOperation::Add) {
+ result = Servo_AnimationValues_Add(*destValue, *valueToAdd).Consume();
+ } else {
+ result = Servo_AnimationValues_Accumulate(*destValue, *valueToAdd, aCount)
+ .Consume();
+ }
+
+ if (!result) {
+ return false;
+ }
+ aDestWrapper->mServoValues[i] = result;
+ }
+
+ return true;
+}
+
+static bool AddOrAccumulate(SMILValue& aDest, const SMILValue& aValueToAdd,
+ CompositeOperation aCompositeOp, uint64_t aCount) {
+ MOZ_ASSERT(aValueToAdd.mType == aDest.mType,
+ "Trying to add mismatching types");
+ MOZ_ASSERT(aValueToAdd.mType == &SMILCSSValueType::sSingleton,
+ "Unexpected SMIL value type");
+ MOZ_ASSERT(aCompositeOp == CompositeOperation::Add ||
+ aCompositeOp == CompositeOperation::Accumulate,
+ "Composite operation should be add or accumulate");
+ MOZ_ASSERT(aCompositeOp != CompositeOperation::Add || aCount == 1,
+ "Count should be 1 if composite operation is add");
+
+ ValueWrapper* destWrapper = ExtractValueWrapper(aDest);
+ const ValueWrapper* valueToAddWrapper = ExtractValueWrapper(aValueToAdd);
+
+ // If both of the values are empty just fail. This can happen in rare cases
+ // such as when the underlying animation produced an empty value.
+ //
+ // Technically, it doesn't matter what we return here since in either case it
+ // will produce the same result: an empty value.
+ if (!destWrapper && !valueToAddWrapper) {
+ return false;
+ }
+
+ nsCSSPropertyID property =
+ valueToAddWrapper ? valueToAddWrapper->mPropID : 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;
+ }
+ // Skip font shorthand since it includes font-size-adjust.
+ if (property == eCSSProperty_font) {
+ return false;
+ }
+
+ return AddOrAccumulateForServo(aDest, valueToAddWrapper, destWrapper,
+ aCompositeOp, aCount);
+}
+
+nsresult SMILCSSValueType::SandwichAdd(SMILValue& aDest,
+ const SMILValue& aValueToAdd) const {
+ return AddOrAccumulate(aDest, aValueToAdd, CompositeOperation::Add, 1)
+ ? NS_OK
+ : NS_ERROR_FAILURE;
+}
+
+nsresult SMILCSSValueType::Add(SMILValue& aDest, const SMILValue& aValueToAdd,
+ 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) {
+ size_t len = aToWrapper.mServoValues.Length();
+ MOZ_ASSERT(!aFromWrapper || aFromWrapper->mServoValues.Length() == len,
+ "From and to values length should be the same if "
+ "The start value exists");
+
+ double squareDistance = 0;
+
+ for (size_t i = 0; i < len; i++) {
+ const RefPtr<StyleAnimationValue>* fromValue =
+ aFromWrapper ? &aFromWrapper->mServoValues[0] : nullptr;
+ const RefPtr<StyleAnimationValue>* toValue = &aToWrapper.mServoValues[0];
+ RefPtr<StyleAnimationValue> zeroValueStorage;
+ if (!FinalizeServoAnimationValues(fromValue, toValue, zeroValueStorage)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ double distance =
+ Servo_AnimationValues_ComputeDistance(*fromValue, *toValue);
+ if (distance < 0.0) {
+ return NS_ERROR_FAILURE;
+ }
+
+ if (len == 1) {
+ aDistance = distance;
+ return NS_OK;
+ }
+ squareDistance += distance * distance;
+ }
+
+ aDistance = sqrt(squareDistance);
+
+ return NS_OK;
+}
+
+nsresult SMILCSSValueType::ComputeDistance(const SMILValue& aFrom,
+ const SMILValue& 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");
+ return ComputeDistanceForServo(fromWrapper, *toWrapper, aDistance);
+}
+
+static nsresult InterpolateForServo(const ValueWrapper* aStartWrapper,
+ const ValueWrapper& aEndWrapper,
+ double aUnitDistance, SMILValue& aResult) {
+ // For discretely-animated properties Servo_AnimationValues_Interpolate will
+ // perform the discrete animation (i.e. 50% flip) and return a success result.
+ // However, SMIL has its own special discrete animation behavior that it uses
+ // when keyTimes are specified, but we won't run that unless that this method
+ // returns a failure to indicate that the property cannot be smoothly
+ // interpolated, i.e. that we need to use a discrete calcMode.
+ //
+ // For shorthands, Servo_Property_IsDiscreteAnimatable will always return
+ // false. That's fine since most shorthands (like 'font' and
+ // 'text-decoration') include non-discrete components. If authors want to
+ // treat all components as discrete then they should use calcMode="discrete".
+ if (Servo_Property_IsDiscreteAnimatable(aEndWrapper.mPropID)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ ServoAnimationValues results;
+ size_t len = aEndWrapper.mServoValues.Length();
+ results.SetCapacity(len);
+ MOZ_ASSERT(!aStartWrapper || aStartWrapper->mServoValues.Length() == len,
+ "Start and end values length should be the same if "
+ "the start value exists");
+ for (size_t i = 0; i < len; i++) {
+ const RefPtr<StyleAnimationValue>* startValue =
+ aStartWrapper ? &aStartWrapper->mServoValues[i] : nullptr;
+ const RefPtr<StyleAnimationValue>* endValue = &aEndWrapper.mServoValues[i];
+ RefPtr<StyleAnimationValue> zeroValueStorage;
+ if (!FinalizeServoAnimationValues(startValue, endValue, zeroValueStorage)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ RefPtr<StyleAnimationValue> result =
+ Servo_AnimationValues_Interpolate(*startValue, *endValue, aUnitDistance)
+ .Consume();
+ if (!result) {
+ return NS_ERROR_FAILURE;
+ }
+ results.AppendElement(result);
+ }
+ aResult.mU.mPtr = new ValueWrapper(aEndWrapper.mPropID, std::move(results));
+
+ return NS_OK;
+}
+
+nsresult SMILCSSValueType::Interpolate(const SMILValue& aStartVal,
+ const SMILValue& aEndVal,
+ double aUnitDistance,
+ SMILValue& aResult) const {
+ MOZ_ASSERT(aStartVal.mType == aEndVal.mType,
+ "Trying to interpolate different types");
+ MOZ_ASSERT(aStartVal.mType == this, "Unexpected types for interpolation");
+ MOZ_ASSERT(aResult.mType == this, "Unexpected result type");
+ 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");
+ return InterpolateForServo(startWrapper, *endWrapper, aUnitDistance, aResult);
+}
+
+static ServoAnimationValues ValueFromStringHelper(
+ nsCSSPropertyID aPropID, Element* aTargetElement,
+ nsPresContext* aPresContext, const ComputedStyle* aComputedStyle,
+ const nsAString& aString) {
+ ServoAnimationValues result;
+
+ Document* doc = aTargetElement->GetComposedDoc();
+ if (!doc) {
+ return result;
+ }
+
+ // Parse property
+ ServoCSSParser::ParsingEnvironment env =
+ ServoCSSParser::GetParsingEnvironment(doc);
+ RefPtr<StyleLockedDeclarationBlock> servoDeclarationBlock =
+ ServoCSSParser::ParseProperty(aPropID, NS_ConvertUTF16toUTF8(aString),
+ env,
+ ParsingMode::AllowUnitlessLength |
+ ParsingMode::AllowAllNumericValues);
+ if (!servoDeclarationBlock) {
+ return result;
+ }
+
+ // Compute value
+ aPresContext->StyleSet()->GetAnimationValues(
+ servoDeclarationBlock, aTargetElement, aComputedStyle, result);
+
+ return result;
+}
+
+// static
+void SMILCSSValueType::ValueFromString(nsCSSPropertyID aPropID,
+ Element* aTargetElement,
+ const nsAString& aString,
+ SMILValue& aValue,
+ bool* aIsContextSensitive) {
+ MOZ_ASSERT(aValue.IsNull(), "Outparam should be null-typed");
+ nsPresContext* presContext =
+ nsContentUtils::GetContextForContent(aTargetElement);
+ if (!presContext) {
+ NS_WARNING("Not parsing animation value; unable to get PresContext");
+ return;
+ }
+
+ Document* doc = aTargetElement->GetComposedDoc();
+ if (doc && !nsStyleUtil::CSPAllowsInlineStyle(nullptr, doc, nullptr, 0, 0,
+ aString, nullptr)) {
+ return;
+ }
+
+ RefPtr<const ComputedStyle> computedStyle =
+ nsComputedDOMStyle::GetComputedStyle(aTargetElement);
+ if (!computedStyle) {
+ return;
+ }
+
+ ServoAnimationValues parsedValues = ValueFromStringHelper(
+ aPropID, aTargetElement, presContext, computedStyle, aString);
+ if (aIsContextSensitive) {
+ // FIXME: Bug 1358955 - detect context-sensitive values and set this value
+ // appropriately.
+ *aIsContextSensitive = false;
+ }
+
+ if (!parsedValues.IsEmpty()) {
+ sSingleton.Init(aValue);
+ aValue.mU.mPtr = new ValueWrapper(aPropID, std::move(parsedValues));
+ }
+}
+
+// static
+SMILValue SMILCSSValueType::ValueFromAnimationValue(
+ nsCSSPropertyID aPropID, Element* aTargetElement,
+ const AnimationValue& aValue) {
+ SMILValue result;
+
+ Document* doc = aTargetElement->GetComposedDoc();
+ // We'd like to avoid serializing |aValue| if possible, and since the
+ // string passed to CSPAllowsInlineStyle is only used for reporting violations
+ // and an intermediate CSS value is not likely to be particularly useful
+ // in that case, we just use a generic placeholder string instead.
+ static const nsLiteralString kPlaceholderText = u"[SVG animation of CSS]"_ns;
+ if (doc && !nsStyleUtil::CSPAllowsInlineStyle(nullptr, doc, nullptr, 0, 0,
+ kPlaceholderText, nullptr)) {
+ return result;
+ }
+
+ sSingleton.Init(result);
+ result.mU.mPtr = new ValueWrapper(aPropID, aValue);
+
+ return result;
+}
+
+// static
+bool SMILCSSValueType::SetPropertyValues(const SMILValue& aValue,
+ DeclarationBlock& aDecl) {
+ MOZ_ASSERT(aValue.mType == &SMILCSSValueType::sSingleton,
+ "Unexpected SMIL value type");
+ const ValueWrapper* wrapper = ExtractValueWrapper(aValue);
+ if (!wrapper) {
+ return false;
+ }
+
+ bool changed = false;
+ for (const auto& value : wrapper->mServoValues) {
+ changed |= Servo_DeclarationBlock_SetPropertyToAnimationValue(aDecl.Raw(),
+ value, {});
+ }
+
+ return changed;
+}
+
+// static
+nsCSSPropertyID SMILCSSValueType::PropertyFromValue(const SMILValue& aValue) {
+ if (aValue.mType != &SMILCSSValueType::sSingleton) {
+ return eCSSProperty_UNKNOWN;
+ }
+
+ const ValueWrapper* wrapper = ExtractValueWrapper(aValue);
+ if (!wrapper) {
+ return eCSSProperty_UNKNOWN;
+ }
+
+ return wrapper->mPropID;
+}
+
+// static
+void SMILCSSValueType::FinalizeValue(SMILValue& aValue,
+ const SMILValue& aValueToMatch) {
+ MOZ_ASSERT(aValue.mType == aValueToMatch.mType, "Incompatible SMIL types");
+ MOZ_ASSERT(aValue.mType == &SMILCSSValueType::sSingleton,
+ "Unexpected SMIL value type");
+
+ ValueWrapper* valueWrapper = ExtractValueWrapper(aValue);
+ // If |aValue| already has a value, there's nothing to do here.
+ if (valueWrapper) {
+ return;
+ }
+
+ const ValueWrapper* valueToMatchWrapper = ExtractValueWrapper(aValueToMatch);
+ if (!valueToMatchWrapper) {
+ MOZ_ASSERT_UNREACHABLE("Value to match is empty");
+ return;
+ }
+
+ ServoAnimationValues zeroValues;
+ zeroValues.SetCapacity(valueToMatchWrapper->mServoValues.Length());
+
+ for (const auto& valueToMatch : valueToMatchWrapper->mServoValues) {
+ RefPtr<StyleAnimationValue> zeroValue =
+ Servo_AnimationValues_GetZeroValue(valueToMatch).Consume();
+ if (!zeroValue) {
+ return;
+ }
+ zeroValues.AppendElement(std::move(zeroValue));
+ }
+ aValue.mU.mPtr =
+ new ValueWrapper(valueToMatchWrapper->mPropID, std::move(zeroValues));
+}
+
+} // namespace mozilla