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"
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
;
22 //----------------------------------------------------------------------
23 // Helper class: AutoChangeIntegerPairNotifier
24 // Stack-based helper class to pair calls to WillChangeIntegerPair and
25 // DidChangeIntegerPair.
26 class MOZ_RAII AutoChangeIntegerPairNotifier
{
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");
37 mUpdateBatch
.emplace(aSVGElement
->GetComposedDoc(), true);
38 mEmptyOrOldValue
= mSVGElement
->WillChangeIntegerPair(
39 mIntegerPair
->mAttrEnum
, mUpdateBatch
.ref());
43 ~AutoChangeIntegerPairNotifier() {
45 mSVGElement
->DidChangeIntegerPair(mIntegerPair
->mAttrEnum
,
46 mEmptyOrOldValue
, mUpdateBatch
.ref());
48 if (mIntegerPair
->mIsAnimated
) {
49 mSVGElement
->AnimationNeedsResample();
54 SVGAnimatedIntegerPair
* const mIntegerPair
;
55 SVGElement
* const mSVGElement
;
56 Maybe
<mozAutoDocUpdate
> mUpdateBatch
;
57 nsAttrValue mEmptyOrOldValue
;
61 MOZ_CONSTINIT
static SVGAttrTearoffTable
<
62 SVGAnimatedIntegerPair
, SVGAnimatedIntegerPair::DOMAnimatedInteger
>
63 sSVGFirstAnimatedIntegerTearoffTable
;
64 MOZ_CONSTINIT
static SVGAttrTearoffTable
<
65 SVGAnimatedIntegerPair
, SVGAnimatedIntegerPair::DOMAnimatedInteger
>
66 sSVGSecondAnimatedIntegerTearoffTable
;
70 static nsresult
ParseIntegerOptionalInteger(const nsAString
& aValue
,
72 nsCharSeparatedTokenizerTemplate
<nsContentUtils::IsHTMLWhitespace
,
73 nsTokenizerFlags::SeparatorOptional
>
74 tokenizer(aValue
, ',');
76 for (i
= 0; i
< 2 && tokenizer
.hasMoreTokens(); ++i
) {
77 if (!SVGContentUtils::ParseInteger(tokenizer
.nextToken(), aValues
[i
])) {
78 return NS_ERROR_DOM_SYNTAX_ERR
;
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
;
94 nsresult
SVGAnimatedIntegerPair::SetBaseValueString(
95 const nsAString
& aValueAsString
, SVGElement
* aSVGElement
) {
98 nsresult rv
= ParseIntegerOptionalInteger(aValueAsString
, val
);
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];
113 mAnimVal
[0] = mBaseVal
[0];
114 mAnimVal
[1] = mBaseVal
[1];
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
) {
136 AutoChangeIntegerPairNotifier
notifier(this, aSVGElement
);
138 mBaseVal
[index
] = aValue
;
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
) {
151 AutoChangeIntegerPairNotifier
notifier(this, aSVGElement
);
153 mBaseVal
[0] = aValue1
;
154 mBaseVal
[1] = aValue2
;
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]) {
167 mAnimVal
[0] = aValue
[0];
168 mAnimVal
[1] = aValue
[1];
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
);
184 sSVGSecondAnimatedIntegerTearoffTable
.AddTearoff(this,
189 return domAnimatedInteger
.forget();
192 SVGAnimatedIntegerPair::DOMAnimatedInteger::~DOMAnimatedInteger() {
193 if (mIndex
== eFirst
) {
194 sSVGFirstAnimatedIntegerTearoffTable
.RemoveTearoff(mVal
);
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 {
210 nsresult rv
= ParseIntegerOptionalInteger(aStr
, values
);
215 SMILValue
val(SVGIntegerPairSMILType::Singleton());
216 val
.mU
.mIntPair
[0] = values
[0];
217 val
.mU
.mIntPair
[1] = values
[1];
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];
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
);
249 } // namespace mozilla