Bug 1936278 - Prevent search mode chiclet from being dismissed when clicking in page...
[gecko.git] / dom / svg / SVGAnimatedIntegerPair.cpp
blob071adfe8a9e680ba5f9447f8120ebec99902ed18
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 "SVGAnimatedIntegerPair.h"
9 #include "nsCharSeparatedTokenizer.h"
10 #include "nsError.h"
11 #include "nsMathUtils.h"
12 #include "SVGAttrTearoffTable.h"
13 #include "SVGIntegerPairSMILType.h"
14 #include "mozAutoDocUpdate.h"
15 #include "mozilla/SMILValue.h"
16 #include "mozilla/SVGContentUtils.h"
18 using namespace mozilla::dom;
20 namespace mozilla {
22 //----------------------------------------------------------------------
23 // Helper class: AutoChangeIntegerPairNotifier
24 // Stack-based helper class to pair calls to WillChangeIntegerPair and
25 // DidChangeIntegerPair.
26 class MOZ_RAII AutoChangeIntegerPairNotifier {
27 public:
28 AutoChangeIntegerPairNotifier(SVGAnimatedIntegerPair* aIntegerPair,
29 SVGElement* aSVGElement, bool aDoSetAttr = true)
30 : mIntegerPair(aIntegerPair),
31 mSVGElement(aSVGElement),
32 mDoSetAttr(aDoSetAttr) {
33 MOZ_ASSERT(mIntegerPair, "Expecting non-null integerPair");
34 MOZ_ASSERT(mSVGElement, "Expecting non-null element");
36 if (mDoSetAttr) {
37 mUpdateBatch.emplace(aSVGElement->GetComposedDoc(), true);
38 mEmptyOrOldValue = mSVGElement->WillChangeIntegerPair(
39 mIntegerPair->mAttrEnum, mUpdateBatch.ref());
43 ~AutoChangeIntegerPairNotifier() {
44 if (mDoSetAttr) {
45 mSVGElement->DidChangeIntegerPair(mIntegerPair->mAttrEnum,
46 mEmptyOrOldValue, mUpdateBatch.ref());
48 if (mIntegerPair->mIsAnimated) {
49 mSVGElement->AnimationNeedsResample();
53 private:
54 SVGAnimatedIntegerPair* const mIntegerPair;
55 SVGElement* const mSVGElement;
56 Maybe<mozAutoDocUpdate> mUpdateBatch;
57 nsAttrValue mEmptyOrOldValue;
58 bool mDoSetAttr;
61 MOZ_CONSTINIT static SVGAttrTearoffTable<
62 SVGAnimatedIntegerPair, SVGAnimatedIntegerPair::DOMAnimatedInteger>
63 sSVGFirstAnimatedIntegerTearoffTable;
64 MOZ_CONSTINIT static SVGAttrTearoffTable<
65 SVGAnimatedIntegerPair, SVGAnimatedIntegerPair::DOMAnimatedInteger>
66 sSVGSecondAnimatedIntegerTearoffTable;
68 /* Implementation */
70 static nsresult ParseIntegerOptionalInteger(const nsAString& aValue,
71 int32_t aValues[2]) {
72 nsCharSeparatedTokenizerTemplate<nsContentUtils::IsHTMLWhitespace,
73 nsTokenizerFlags::SeparatorOptional>
74 tokenizer(aValue, ',');
75 uint32_t i;
76 for (i = 0; i < 2 && tokenizer.hasMoreTokens(); ++i) {
77 if (!SVGContentUtils::ParseInteger(tokenizer.nextToken(), aValues[i])) {
78 return NS_ERROR_DOM_SYNTAX_ERR;
81 if (i == 1) {
82 aValues[1] = aValues[0];
85 if (i == 0 || // Too few values.
86 tokenizer.hasMoreTokens() || // Too many values.
87 tokenizer.separatorAfterCurrentToken()) { // Trailing comma.
88 return NS_ERROR_DOM_SYNTAX_ERR;
91 return NS_OK;
94 nsresult SVGAnimatedIntegerPair::SetBaseValueString(
95 const nsAString& aValueAsString, SVGElement* aSVGElement) {
96 int32_t val[2];
98 nsresult rv = ParseIntegerOptionalInteger(aValueAsString, val);
100 if (NS_FAILED(rv)) {
101 return rv;
104 // We don't need to call DidChange* here - we're only called by
105 // SVGElement::ParseAttribute under Element::SetAttr,
106 // which takes care of notifying.
107 AutoChangeIntegerPairNotifier notifier(this, aSVGElement, false);
109 mBaseVal[0] = val[0];
110 mBaseVal[1] = val[1];
111 mIsBaseSet = true;
112 if (!mIsAnimated) {
113 mAnimVal[0] = mBaseVal[0];
114 mAnimVal[1] = mBaseVal[1];
116 return NS_OK;
119 void SVGAnimatedIntegerPair::GetBaseValueString(
120 nsAString& aValueAsString) const {
121 aValueAsString.Truncate();
122 aValueAsString.AppendInt(mBaseVal[0]);
123 if (mBaseVal[0] != mBaseVal[1]) {
124 aValueAsString.AppendLiteral(", ");
125 aValueAsString.AppendInt(mBaseVal[1]);
129 void SVGAnimatedIntegerPair::SetBaseValue(int32_t aValue, PairIndex aPairIndex,
130 SVGElement* aSVGElement) {
131 uint32_t index = (aPairIndex == eFirst ? 0 : 1);
132 if (mIsBaseSet && mBaseVal[index] == aValue) {
133 return;
136 AutoChangeIntegerPairNotifier notifier(this, aSVGElement);
138 mBaseVal[index] = aValue;
139 mIsBaseSet = true;
140 if (!mIsAnimated) {
141 mAnimVal[index] = aValue;
145 void SVGAnimatedIntegerPair::SetBaseValues(int32_t aValue1, int32_t aValue2,
146 SVGElement* aSVGElement) {
147 if (mIsBaseSet && mBaseVal[0] == aValue1 && mBaseVal[1] == aValue2) {
148 return;
151 AutoChangeIntegerPairNotifier notifier(this, aSVGElement);
153 mBaseVal[0] = aValue1;
154 mBaseVal[1] = aValue2;
155 mIsBaseSet = true;
156 if (!mIsAnimated) {
157 mAnimVal[0] = aValue1;
158 mAnimVal[1] = aValue2;
162 void SVGAnimatedIntegerPair::SetAnimValue(const int32_t aValue[2],
163 SVGElement* aSVGElement) {
164 if (mIsAnimated && mAnimVal[0] == aValue[0] && mAnimVal[1] == aValue[1]) {
165 return;
167 mAnimVal[0] = aValue[0];
168 mAnimVal[1] = aValue[1];
169 mIsAnimated = true;
170 aSVGElement->DidAnimateIntegerPair(mAttrEnum);
173 already_AddRefed<DOMSVGAnimatedInteger>
174 SVGAnimatedIntegerPair::ToDOMAnimatedInteger(PairIndex aIndex,
175 SVGElement* aSVGElement) {
176 RefPtr<DOMAnimatedInteger> domAnimatedInteger =
177 aIndex == eFirst ? sSVGFirstAnimatedIntegerTearoffTable.GetTearoff(this)
178 : sSVGSecondAnimatedIntegerTearoffTable.GetTearoff(this);
179 if (!domAnimatedInteger) {
180 domAnimatedInteger = new DOMAnimatedInteger(this, aIndex, aSVGElement);
181 if (aIndex == eFirst) {
182 sSVGFirstAnimatedIntegerTearoffTable.AddTearoff(this, domAnimatedInteger);
183 } else {
184 sSVGSecondAnimatedIntegerTearoffTable.AddTearoff(this,
185 domAnimatedInteger);
189 return domAnimatedInteger.forget();
192 SVGAnimatedIntegerPair::DOMAnimatedInteger::~DOMAnimatedInteger() {
193 if (mIndex == eFirst) {
194 sSVGFirstAnimatedIntegerTearoffTable.RemoveTearoff(mVal);
195 } else {
196 sSVGSecondAnimatedIntegerTearoffTable.RemoveTearoff(mVal);
200 UniquePtr<SMILAttr> SVGAnimatedIntegerPair::ToSMILAttr(
201 SVGElement* aSVGElement) {
202 return MakeUnique<SMILIntegerPair>(this, aSVGElement);
205 nsresult SVGAnimatedIntegerPair::SMILIntegerPair::ValueFromString(
206 const nsAString& aStr, const dom::SVGAnimationElement* /*aSrcElement*/,
207 SMILValue& aValue, bool& aPreventCachingOfSandwich) const {
208 int32_t values[2];
210 nsresult rv = ParseIntegerOptionalInteger(aStr, values);
211 if (NS_FAILED(rv)) {
212 return rv;
215 SMILValue val(SVGIntegerPairSMILType::Singleton());
216 val.mU.mIntPair[0] = values[0];
217 val.mU.mIntPair[1] = values[1];
218 aValue = val;
220 return NS_OK;
223 SMILValue SVGAnimatedIntegerPair::SMILIntegerPair::GetBaseValue() const {
224 SMILValue val(SVGIntegerPairSMILType::Singleton());
225 val.mU.mIntPair[0] = mVal->mBaseVal[0];
226 val.mU.mIntPair[1] = mVal->mBaseVal[1];
227 return val;
230 void SVGAnimatedIntegerPair::SMILIntegerPair::ClearAnimValue() {
231 if (mVal->mIsAnimated) {
232 mVal->mIsAnimated = false;
233 mVal->mAnimVal[0] = mVal->mBaseVal[0];
234 mVal->mAnimVal[1] = mVal->mBaseVal[1];
235 mSVGElement->DidAnimateIntegerPair(mVal->mAttrEnum);
239 nsresult SVGAnimatedIntegerPair::SMILIntegerPair::SetAnimValue(
240 const SMILValue& aValue) {
241 NS_ASSERTION(aValue.mType == SVGIntegerPairSMILType::Singleton(),
242 "Unexpected type to assign animated value");
243 if (aValue.mType == SVGIntegerPairSMILType::Singleton()) {
244 mVal->SetAnimValue(aValue.mU.mIntPair, mSVGElement);
246 return NS_OK;
249 } // namespace mozilla