Bug 1936278 - Prevent search mode chiclet from being dismissed when clicking in page...
[gecko.git] / dom / svg / SVGAnimatedEnumeration.cpp
blob489a0d59b321d61c631db6f2d1f36c2ff8858021
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"
11 #include "nsAtom.h"
12 #include "nsError.h"
13 #include "SMILEnumType.h"
14 #include "SVGAttrTearoffTable.h"
16 using namespace mozilla::dom;
18 namespace mozilla {
20 //----------------------------------------------------------------------
21 // Helper class: AutoChangeEnumNotifier
22 // Stack-based helper class to ensure DidChangeEnum is called.
23 class MOZ_RAII AutoChangeEnumNotifier {
24 public:
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() {
33 if (mDoSetAttr) {
34 mSVGElement->DidChangeEnum(mEnum->mAttrEnum);
36 if (mEnum->mIsAnimated) {
37 mSVGElement->AnimationNeedsResample();
41 private:
42 SVGAnimatedEnumeration* const mEnum;
43 SVGElement* const mSVGElement;
44 bool mDoSetAttr;
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) {
68 mIsBaseSet = true;
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;
75 if (!mIsAnimated) {
76 mAnimVal = mBaseVal;
79 return true;
81 mapping++;
84 return false;
87 nsAtom* SVGAnimatedEnumeration::GetBaseValueAtom(SVGElement* aSVGElement) {
88 const SVGEnumMapping* mapping = GetMapping(aSVGElement);
90 while (mapping && mapping->mKey) {
91 if (mBaseVal == mapping->mVal) {
92 return mapping->mKey;
94 mapping++;
96 NS_ERROR("unknown enumeration value");
97 return nsGkAtoms::_empty;
100 void SVGAnimatedEnumeration::SetBaseValue(uint16_t aValue,
101 SVGElement* aSVGElement,
102 ErrorResult& aRv) {
103 const SVGEnumMapping* mapping = GetMapping(aSVGElement);
105 while (mapping && mapping->mKey) {
106 if (mapping->mVal == aValue) {
107 if (!mIsBaseSet || mBaseVal != uint8_t(aValue)) {
108 mIsBaseSet = true;
109 AutoChangeEnumNotifier notifier(this, aSVGElement);
111 mBaseVal = uint8_t(aValue);
112 if (!mIsAnimated) {
113 mAnimVal = mBaseVal;
116 return;
118 mapping++;
120 return aRv.ThrowTypeError("Invalid SVGAnimatedEnumeration base value");
123 void SVGAnimatedEnumeration::SetAnimValue(uint16_t aValue,
124 SVGElement* aSVGElement) {
125 if (mIsAnimated && aValue == mAnimVal) {
126 return;
128 mAnimVal = aValue;
129 mIsAnimated = true;
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);
158 if (valAtom) {
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;
165 aValue = val;
166 return NS_OK;
168 mapping++;
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;
180 return val;
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);
200 return NS_OK;
203 } // namespace mozilla