Bug 1936278 - Prevent search mode chiclet from being dismissed when clicking in page...
[gecko.git] / dom / svg / SVGAnimatedNumberPair.cpp
blob579094e78bcb911c5bdbb3f2751fd26d27d8e338
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "SVGAnimatedNumberPair.h"
9 #include "nsCharSeparatedTokenizer.h"
10 #include "SVGAttrTearoffTable.h"
11 #include "SVGNumberPairSMILType.h"
12 #include "mozilla/SMILValue.h"
13 #include "mozilla/SVGContentUtils.h"
14 #include "nsContentUtils.h"
16 using namespace mozilla::dom;
18 namespace mozilla {
20 //----------------------------------------------------------------------
21 // Helper class: AutoChangeNumberPairNotifier
22 // Stack-based helper class to pair calls to WillChangeNumberPair and
23 // DidChangeNumberPair.
24 class MOZ_RAII AutoChangeNumberPairNotifier {
25 public:
26 AutoChangeNumberPairNotifier(SVGAnimatedNumberPair* aNumberPair,
27 SVGElement* aSVGElement, bool aDoSetAttr = true)
28 : mNumberPair(aNumberPair),
29 mSVGElement(aSVGElement),
30 mDoSetAttr(aDoSetAttr) {
31 MOZ_ASSERT(mNumberPair, "Expecting non-null numberPair");
32 MOZ_ASSERT(mSVGElement, "Expecting non-null element");
34 if (mDoSetAttr) {
35 mEmptyOrOldValue =
36 mSVGElement->WillChangeNumberPair(mNumberPair->mAttrEnum);
40 ~AutoChangeNumberPairNotifier() {
41 if (mDoSetAttr) {
42 mSVGElement->DidChangeNumberPair(mNumberPair->mAttrEnum,
43 mEmptyOrOldValue);
45 if (mNumberPair->mIsAnimated) {
46 mSVGElement->AnimationNeedsResample();
50 private:
51 SVGAnimatedNumberPair* const mNumberPair;
52 SVGElement* const mSVGElement;
53 nsAttrValue mEmptyOrOldValue;
54 bool mDoSetAttr;
57 MOZ_CONSTINIT static SVGAttrTearoffTable<
58 SVGAnimatedNumberPair, SVGAnimatedNumberPair::DOMAnimatedNumber>
59 sSVGFirstAnimatedNumberTearoffTable;
60 MOZ_CONSTINIT static SVGAttrTearoffTable<
61 SVGAnimatedNumberPair, SVGAnimatedNumberPair::DOMAnimatedNumber>
62 sSVGSecondAnimatedNumberTearoffTable;
64 static nsresult ParseNumberOptionalNumber(const nsAString& aValue,
65 float aValues[2]) {
66 nsCharSeparatedTokenizerTemplate<nsContentUtils::IsHTMLWhitespace,
67 nsTokenizerFlags::SeparatorOptional>
68 tokenizer(aValue, ',');
69 uint32_t i;
70 for (i = 0; i < 2 && tokenizer.hasMoreTokens(); ++i) {
71 if (!SVGContentUtils::ParseNumber(tokenizer.nextToken(), aValues[i])) {
72 return NS_ERROR_DOM_SYNTAX_ERR;
75 if (i == 1) {
76 aValues[1] = aValues[0];
79 if (i == 0 || // Too few values.
80 tokenizer.hasMoreTokens() || // Too many values.
81 tokenizer.separatorAfterCurrentToken()) { // Trailing comma.
82 return NS_ERROR_DOM_SYNTAX_ERR;
85 return NS_OK;
88 nsresult SVGAnimatedNumberPair::SetBaseValueString(
89 const nsAString& aValueAsString, SVGElement* aSVGElement) {
90 float val[2];
92 nsresult rv = ParseNumberOptionalNumber(aValueAsString, val);
93 if (NS_FAILED(rv)) {
94 return rv;
97 // We don't need to call Will/DidChange* here - we're only called by
98 // SVGElement::ParseAttribute under Element::SetAttr,
99 // which takes care of notifying.
100 AutoChangeNumberPairNotifier notifier(this, aSVGElement, false);
102 mBaseVal[0] = val[0];
103 mBaseVal[1] = val[1];
104 mIsBaseSet = true;
105 if (!mIsAnimated) {
106 mAnimVal[0] = mBaseVal[0];
107 mAnimVal[1] = mBaseVal[1];
110 return NS_OK;
113 void SVGAnimatedNumberPair::GetBaseValueString(
114 nsAString& aValueAsString) const {
115 aValueAsString.Truncate();
116 aValueAsString.AppendFloat(mBaseVal[0]);
117 if (mBaseVal[0] != mBaseVal[1]) {
118 aValueAsString.AppendLiteral(", ");
119 aValueAsString.AppendFloat(mBaseVal[1]);
123 void SVGAnimatedNumberPair::SetBaseValue(float aValue, PairIndex aPairIndex,
124 SVGElement* aSVGElement) {
125 uint32_t index = (aPairIndex == eFirst ? 0 : 1);
126 if (mIsBaseSet && mBaseVal[index] == aValue) {
127 return;
130 AutoChangeNumberPairNotifier notifier(this, aSVGElement);
132 mBaseVal[index] = aValue;
133 mIsBaseSet = true;
134 if (!mIsAnimated) {
135 mAnimVal[index] = aValue;
139 void SVGAnimatedNumberPair::SetBaseValues(float aValue1, float aValue2,
140 SVGElement* aSVGElement) {
141 if (mIsBaseSet && mBaseVal[0] == aValue1 && mBaseVal[1] == aValue2) {
142 return;
145 AutoChangeNumberPairNotifier notifier(this, aSVGElement);
147 mBaseVal[0] = aValue1;
148 mBaseVal[1] = aValue2;
149 mIsBaseSet = true;
150 if (!mIsAnimated) {
151 mAnimVal[0] = aValue1;
152 mAnimVal[1] = aValue2;
156 void SVGAnimatedNumberPair::SetAnimValue(const float aValue[2],
157 SVGElement* aSVGElement) {
158 if (mIsAnimated && mAnimVal[0] == aValue[0] && mAnimVal[1] == aValue[1]) {
159 return;
161 mAnimVal[0] = aValue[0];
162 mAnimVal[1] = aValue[1];
163 mIsAnimated = true;
164 aSVGElement->DidAnimateNumberPair(mAttrEnum);
167 already_AddRefed<DOMSVGAnimatedNumber>
168 SVGAnimatedNumberPair::ToDOMAnimatedNumber(PairIndex aIndex,
169 SVGElement* aSVGElement) {
170 RefPtr<DOMAnimatedNumber> domAnimatedNumber =
171 aIndex == eFirst ? sSVGFirstAnimatedNumberTearoffTable.GetTearoff(this)
172 : sSVGSecondAnimatedNumberTearoffTable.GetTearoff(this);
173 if (!domAnimatedNumber) {
174 domAnimatedNumber = new DOMAnimatedNumber(this, aIndex, aSVGElement);
175 if (aIndex == eFirst) {
176 sSVGFirstAnimatedNumberTearoffTable.AddTearoff(this, domAnimatedNumber);
177 } else {
178 sSVGSecondAnimatedNumberTearoffTable.AddTearoff(this, domAnimatedNumber);
182 return domAnimatedNumber.forget();
185 SVGAnimatedNumberPair::DOMAnimatedNumber::~DOMAnimatedNumber() {
186 if (mIndex == eFirst) {
187 sSVGFirstAnimatedNumberTearoffTable.RemoveTearoff(mVal);
188 } else {
189 sSVGSecondAnimatedNumberTearoffTable.RemoveTearoff(mVal);
193 UniquePtr<SMILAttr> SVGAnimatedNumberPair::ToSMILAttr(SVGElement* aSVGElement) {
194 return MakeUnique<SMILNumberPair>(this, aSVGElement);
197 nsresult SVGAnimatedNumberPair::SMILNumberPair::ValueFromString(
198 const nsAString& aStr, const dom::SVGAnimationElement* /*aSrcElement*/,
199 SMILValue& aValue, bool& aPreventCachingOfSandwich) const {
200 float values[2];
202 nsresult rv = ParseNumberOptionalNumber(aStr, values);
203 if (NS_FAILED(rv)) {
204 return rv;
207 SMILValue val(&SVGNumberPairSMILType::sSingleton);
208 val.mU.mNumberPair[0] = values[0];
209 val.mU.mNumberPair[1] = values[1];
210 aValue = val;
212 return NS_OK;
215 SMILValue SVGAnimatedNumberPair::SMILNumberPair::GetBaseValue() const {
216 SMILValue val(&SVGNumberPairSMILType::sSingleton);
217 val.mU.mNumberPair[0] = mVal->mBaseVal[0];
218 val.mU.mNumberPair[1] = mVal->mBaseVal[1];
219 return val;
222 void SVGAnimatedNumberPair::SMILNumberPair::ClearAnimValue() {
223 if (mVal->mIsAnimated) {
224 mVal->mIsAnimated = false;
225 mVal->mAnimVal[0] = mVal->mBaseVal[0];
226 mVal->mAnimVal[1] = mVal->mBaseVal[1];
227 mSVGElement->DidAnimateNumberPair(mVal->mAttrEnum);
231 nsresult SVGAnimatedNumberPair::SMILNumberPair::SetAnimValue(
232 const SMILValue& aValue) {
233 NS_ASSERTION(aValue.mType == &SVGNumberPairSMILType::sSingleton,
234 "Unexpected type to assign animated value");
235 if (aValue.mType == &SVGNumberPairSMILType::sSingleton) {
236 mVal->SetAnimValue(aValue.mU.mNumberPair, mSVGElement);
238 return NS_OK;
241 } // namespace mozilla