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/. */
6
7 #include "nsError.h"
8 #include "nsSVGAttrTearoffTable.h"
9 #include "nsSVGEnum.h"
10 #include "nsIAtom.h"
11 #include "nsSVGElement.h"
12 #include "nsSMILValue.h"
13 #include "SMILEnumType.h"
14
15 using namespace mozilla;
16 using namespace mozilla::dom;
17
18 static nsSVGAttrTearoffTable<nsSVGEnum, nsSVGEnum::DOMAnimatedEnum>
19 sSVGAnimatedEnumTearoffTable;
20
21 nsSVGEnumMapping *
GetMapping(nsSVGElement * aSVGElement)22 nsSVGEnum::GetMapping(nsSVGElement *aSVGElement)
23 {
24 nsSVGElement::EnumAttributesInfo info = aSVGElement->GetEnumInfo();
25
26 NS_ASSERTION(info.mEnumCount > 0 && mAttrEnum < info.mEnumCount,
27 "mapping request for a non-attrib enum");
28
29 return info.mEnumInfo[mAttrEnum].mMapping;
30 }
31
32 nsresult
SetBaseValueAtom(const nsIAtom * aValue,nsSVGElement * aSVGElement)33 nsSVGEnum::SetBaseValueAtom(const nsIAtom* aValue, nsSVGElement *aSVGElement)
34 {
35 nsSVGEnumMapping *mapping = GetMapping(aSVGElement);
36
37 while (mapping && mapping->mKey) {
38 if (aValue == *(mapping->mKey)) {
39 mIsBaseSet = true;
40 if (mBaseVal != mapping->mVal) {
41 mBaseVal = mapping->mVal;
42 if (!mIsAnimated) {
43 mAnimVal = mBaseVal;
44 }
45 else {
46 aSVGElement->AnimationNeedsResample();
47 }
48 // We don't need to call DidChange* here - we're only called by
49 // nsSVGElement::ParseAttribute under Element::SetAttr,
50 // which takes care of notifying.
51 }
52 return NS_OK;
53 }
54 mapping++;
55 }
56
57 // only a warning since authors may mistype attribute values
58 NS_WARNING("unknown enumeration key");
59 return NS_ERROR_DOM_SYNTAX_ERR;
60 }
61
62 nsIAtom*
GetBaseValueAtom(nsSVGElement * aSVGElement)63 nsSVGEnum::GetBaseValueAtom(nsSVGElement *aSVGElement)
64 {
65 nsSVGEnumMapping *mapping = GetMapping(aSVGElement);
66
67 while (mapping && mapping->mKey) {
68 if (mBaseVal == mapping->mVal) {
69 return *mapping->mKey;
70 }
71 mapping++;
72 }
73 NS_ERROR("unknown enumeration value");
74 return nsGkAtoms::_empty;
75 }
76
77 nsresult
SetBaseValue(uint16_t aValue,nsSVGElement * aSVGElement)78 nsSVGEnum::SetBaseValue(uint16_t aValue,
79 nsSVGElement *aSVGElement)
80 {
81 nsSVGEnumMapping *mapping = GetMapping(aSVGElement);
82
83 while (mapping && mapping->mKey) {
84 if (mapping->mVal == aValue) {
85 mIsBaseSet = true;
86 if (mBaseVal != uint8_t(aValue)) {
87 mBaseVal = uint8_t(aValue);
88 if (!mIsAnimated) {
89 mAnimVal = mBaseVal;
90 }
91 else {
92 aSVGElement->AnimationNeedsResample();
93 }
94 aSVGElement->DidChangeEnum(mAttrEnum);
95 }
96 return NS_OK;
97 }
98 mapping++;
99 }
100 return NS_ERROR_DOM_SYNTAX_ERR;
101 }
102
103 void
SetAnimValue(uint16_t aValue,nsSVGElement * aSVGElement)104 nsSVGEnum::SetAnimValue(uint16_t aValue, nsSVGElement *aSVGElement)
105 {
106 if (mIsAnimated && aValue == mAnimVal) {
107 return;
108 }
109 mAnimVal = aValue;
110 mIsAnimated = true;
111 aSVGElement->DidAnimateEnum(mAttrEnum);
112 }
113
114 already_AddRefed<SVGAnimatedEnumeration>
ToDOMAnimatedEnum(nsSVGElement * aSVGElement)115 nsSVGEnum::ToDOMAnimatedEnum(nsSVGElement* aSVGElement)
116 {
117 RefPtr<DOMAnimatedEnum> domAnimatedEnum =
118 sSVGAnimatedEnumTearoffTable.GetTearoff(this);
119 if (!domAnimatedEnum) {
120 domAnimatedEnum = new DOMAnimatedEnum(this, aSVGElement);
121 sSVGAnimatedEnumTearoffTable.AddTearoff(this, domAnimatedEnum);
122 }
123
124 return domAnimatedEnum.forget();
125 }
126
~DOMAnimatedEnum()127 nsSVGEnum::DOMAnimatedEnum::~DOMAnimatedEnum()
128 {
129 sSVGAnimatedEnumTearoffTable.RemoveTearoff(mVal);
130 }
131
132 nsISMILAttr*
ToSMILAttr(nsSVGElement * aSVGElement)133 nsSVGEnum::ToSMILAttr(nsSVGElement *aSVGElement)
134 {
135 return new SMILEnum(this, aSVGElement);
136 }
137
138 nsresult
ValueFromString(const nsAString & aStr,const dom::SVGAnimationElement *,nsSMILValue & aValue,bool & aPreventCachingOfSandwich) const139 nsSVGEnum::SMILEnum::ValueFromString(const nsAString& aStr,
140 const dom::SVGAnimationElement* /*aSrcElement*/,
141 nsSMILValue& aValue,
142 bool& aPreventCachingOfSandwich) const
143 {
144 nsIAtom *valAtom = NS_GetStaticAtom(aStr);
145 if (valAtom) {
146 nsSVGEnumMapping *mapping = mVal->GetMapping(mSVGElement);
147
148 while (mapping && mapping->mKey) {
149 if (valAtom == *(mapping->mKey)) {
150 nsSMILValue val(SMILEnumType::Singleton());
151 val.mU.mUint = mapping->mVal;
152 aValue = val;
153 aPreventCachingOfSandwich = false;
154 return NS_OK;
155 }
156 mapping++;
157 }
158 }
159
160 // only a warning since authors may mistype attribute values
161 NS_WARNING("unknown enumeration key");
162 return NS_ERROR_FAILURE;
163 }
164
165 nsSMILValue
GetBaseValue() const166 nsSVGEnum::SMILEnum::GetBaseValue() const
167 {
168 nsSMILValue val(SMILEnumType::Singleton());
169 val.mU.mUint = mVal->mBaseVal;
170 return val;
171 }
172
173 void
ClearAnimValue()174 nsSVGEnum::SMILEnum::ClearAnimValue()
175 {
176 if (mVal->mIsAnimated) {
177 mVal->mIsAnimated = false;
178 mVal->mAnimVal = mVal->mBaseVal;
179 mSVGElement->DidAnimateEnum(mVal->mAttrEnum);
180 }
181 }
182
183 nsresult
SetAnimValue(const nsSMILValue & aValue)184 nsSVGEnum::SMILEnum::SetAnimValue(const nsSMILValue& aValue)
185 {
186 NS_ASSERTION(aValue.mType == SMILEnumType::Singleton(),
187 "Unexpected type to assign animated value");
188 if (aValue.mType == SMILEnumType::Singleton()) {
189 MOZ_ASSERT(aValue.mU.mUint <= USHRT_MAX,
190 "Very large enumerated value - too big for uint16_t");
191 mVal->SetAnimValue(uint16_t(aValue.mU.mUint), mSVGElement);
192 }
193 return NS_OK;
194 }
195