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 "SVGAnimatedEnumeration.h"
9 #include "mozilla/dom/SVGElement.h"
10 #include "mozilla/SMILValue.h"
13 #include "SMILEnumType.h"
14 #include "SVGAttrTearoffTable.h"
16 using namespace mozilla::dom
;
20 //----------------------------------------------------------------------
21 // Helper class: AutoChangeEnumNotifier
22 // Stack-based helper class to ensure DidChangeEnum is called.
23 class MOZ_RAII AutoChangeEnumNotifier
{
25 AutoChangeEnumNotifier(SVGAnimatedEnumeration
* aEnum
, SVGElement
* aSVGElement
,
26 bool aDoSetAttr
= true)
27 : mEnum(aEnum
), mSVGElement(aSVGElement
), mDoSetAttr(aDoSetAttr
) {
28 MOZ_ASSERT(mEnum
, "Expecting non-null enum");
29 MOZ_ASSERT(mSVGElement
, "Expecting non-null element");
32 ~AutoChangeEnumNotifier() {
34 mSVGElement
->DidChangeEnum(mEnum
->mAttrEnum
);
36 if (mEnum
->mIsAnimated
) {
37 mSVGElement
->AnimationNeedsResample();
42 SVGAnimatedEnumeration
* const mEnum
;
43 SVGElement
* const mSVGElement
;
47 MOZ_CONSTINIT
static SVGAttrTearoffTable
<
48 SVGAnimatedEnumeration
, SVGAnimatedEnumeration::DOMAnimatedEnum
>
49 sSVGAnimatedEnumTearoffTable
;
51 const SVGEnumMapping
* SVGAnimatedEnumeration::GetMapping(
52 SVGElement
* aSVGElement
) {
53 SVGElement::EnumAttributesInfo info
= aSVGElement
->GetEnumInfo();
55 NS_ASSERTION(info
.mCount
> 0 && mAttrEnum
< info
.mCount
,
56 "mapping request for a non-attrib enum");
58 return info
.mInfos
[mAttrEnum
].mMapping
;
61 bool SVGAnimatedEnumeration::SetBaseValueAtom(const nsAtom
* aValue
,
62 SVGElement
* aSVGElement
) {
63 const SVGEnumMapping
* mapping
= GetMapping(aSVGElement
);
65 while (mapping
&& mapping
->mKey
) {
66 if (aValue
== mapping
->mKey
) {
67 if (!mIsBaseSet
|| mBaseVal
!= mapping
->mVal
) {
69 // We don't need to call DidChange* here - we're only called by
70 // SVGElement::ParseAttribute under Element::SetAttr,
71 // which takes care of notifying.
72 AutoChangeEnumNotifier
notifier(this, aSVGElement
, false);
74 mBaseVal
= mapping
->mVal
;
87 nsAtom
* SVGAnimatedEnumeration::GetBaseValueAtom(SVGElement
* aSVGElement
) {
88 const SVGEnumMapping
* mapping
= GetMapping(aSVGElement
);
90 while (mapping
&& mapping
->mKey
) {
91 if (mBaseVal
== mapping
->mVal
) {
96 NS_ERROR("unknown enumeration value");
97 return nsGkAtoms::_empty
;
100 void SVGAnimatedEnumeration::SetBaseValue(uint16_t aValue
,
101 SVGElement
* aSVGElement
,
103 const SVGEnumMapping
* mapping
= GetMapping(aSVGElement
);
105 while (mapping
&& mapping
->mKey
) {
106 if (mapping
->mVal
== aValue
) {
107 if (!mIsBaseSet
|| mBaseVal
!= uint8_t(aValue
)) {
109 AutoChangeEnumNotifier
notifier(this, aSVGElement
);
111 mBaseVal
= uint8_t(aValue
);
120 return aRv
.ThrowTypeError("Invalid SVGAnimatedEnumeration base value");
123 void SVGAnimatedEnumeration::SetAnimValue(uint16_t aValue
,
124 SVGElement
* aSVGElement
) {
125 if (mIsAnimated
&& aValue
== mAnimVal
) {
130 aSVGElement
->DidAnimateEnum(mAttrEnum
);
133 already_AddRefed
<DOMSVGAnimatedEnumeration
>
134 SVGAnimatedEnumeration::ToDOMAnimatedEnum(SVGElement
* aSVGElement
) {
135 RefPtr
<DOMAnimatedEnum
> domAnimatedEnum
=
136 sSVGAnimatedEnumTearoffTable
.GetTearoff(this);
137 if (!domAnimatedEnum
) {
138 domAnimatedEnum
= new DOMAnimatedEnum(this, aSVGElement
);
139 sSVGAnimatedEnumTearoffTable
.AddTearoff(this, domAnimatedEnum
);
142 return domAnimatedEnum
.forget();
145 SVGAnimatedEnumeration::DOMAnimatedEnum::~DOMAnimatedEnum() {
146 sSVGAnimatedEnumTearoffTable
.RemoveTearoff(mVal
);
149 UniquePtr
<SMILAttr
> SVGAnimatedEnumeration::ToSMILAttr(
150 SVGElement
* aSVGElement
) {
151 return MakeUnique
<SMILEnum
>(this, aSVGElement
);
154 nsresult
SVGAnimatedEnumeration::SMILEnum::ValueFromString(
155 const nsAString
& aStr
, const SVGAnimationElement
* /*aSrcElement*/,
156 SMILValue
& aValue
, bool& aPreventCachingOfSandwich
) const {
157 nsAtom
* valAtom
= NS_GetStaticAtom(aStr
);
159 const SVGEnumMapping
* mapping
= mVal
->GetMapping(mSVGElement
);
161 while (mapping
&& mapping
->mKey
) {
162 if (valAtom
== mapping
->mKey
) {
163 SMILValue
val(SMILEnumType::Singleton());
164 val
.mU
.mUint
= mapping
->mVal
;
172 // only a warning since authors may mistype attribute values
173 NS_WARNING("unknown enumeration key");
174 return NS_ERROR_FAILURE
;
177 SMILValue
SVGAnimatedEnumeration::SMILEnum::GetBaseValue() const {
178 SMILValue
val(SMILEnumType::Singleton());
179 val
.mU
.mUint
= mVal
->mBaseVal
;
183 void SVGAnimatedEnumeration::SMILEnum::ClearAnimValue() {
184 if (mVal
->mIsAnimated
) {
185 mVal
->mIsAnimated
= false;
186 mVal
->mAnimVal
= mVal
->mBaseVal
;
187 mSVGElement
->DidAnimateEnum(mVal
->mAttrEnum
);
191 nsresult
SVGAnimatedEnumeration::SMILEnum::SetAnimValue(
192 const SMILValue
& aValue
) {
193 NS_ASSERTION(aValue
.mType
== SMILEnumType::Singleton(),
194 "Unexpected type to assign animated value");
195 if (aValue
.mType
== SMILEnumType::Singleton()) {
196 MOZ_ASSERT(aValue
.mU
.mUint
<= USHRT_MAX
,
197 "Very large enumerated value - too big for uint16_t");
198 mVal
->SetAnimValue(uint16_t(aValue
.mU
.mUint
), mSVGElement
);
203 } // namespace mozilla