Bug 1936278 - Prevent search mode chiclet from being dismissed when clicking in page...
[gecko.git] / dom / svg / SVGAnimatedNumber.cpp
blob74049c2c3db0bb9e3e4d52ea86d00a94a5f59759
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 "SVGAnimatedNumber.h"
9 #include "mozilla/Attributes.h"
10 #include "mozilla/SMILValue.h"
11 #include "mozilla/SVGContentUtils.h"
12 #include "nsContentUtils.h"
13 #include "SMILFloatType.h"
14 #include "SVGAttrTearoffTable.h"
16 using namespace mozilla::dom;
18 namespace mozilla {
20 /* Implementation */
22 //----------------------------------------------------------------------
23 // Helper class: AutoChangeNumberNotifier
24 // Stack-based helper class to ensure DidChangeNumber is called.
25 class MOZ_RAII AutoChangeNumberNotifier {
26 public:
27 AutoChangeNumberNotifier(SVGAnimatedNumber* aNumber, SVGElement* aSVGElement)
28 : mNumber(aNumber), mSVGElement(aSVGElement) {
29 MOZ_ASSERT(mNumber, "Expecting non-null number");
30 MOZ_ASSERT(mSVGElement, "Expecting non-null element");
33 ~AutoChangeNumberNotifier() {
34 mSVGElement->DidChangeNumber(mNumber->mAttrEnum);
35 if (mNumber->mIsAnimated) {
36 mSVGElement->AnimationNeedsResample();
40 private:
41 SVGAnimatedNumber* const mNumber;
42 SVGElement* const mSVGElement;
45 MOZ_CONSTINIT static SVGAttrTearoffTable<SVGAnimatedNumber,
46 SVGAnimatedNumber::DOMAnimatedNumber>
47 sSVGAnimatedNumberTearoffTable;
49 static bool GetValueFromString(const nsAString& aString,
50 bool aPercentagesAllowed, float& aValue) {
51 bool success;
52 auto token = SVGContentUtils::GetAndEnsureOneToken(aString, success);
54 if (!success) {
55 return false;
58 nsAString::const_iterator iter, end;
59 token.BeginReading(iter);
60 token.EndReading(end);
62 if (!SVGContentUtils::ParseNumber(iter, end, aValue)) {
63 return false;
66 if (aPercentagesAllowed) {
67 const nsAString& units = Substring(iter, end);
68 if (units.EqualsLiteral("%")) {
69 aValue /= 100;
70 return true;
74 return iter == end;
77 nsresult SVGAnimatedNumber::SetBaseValueString(const nsAString& aValueAsString,
78 SVGElement* aSVGElement) {
79 float val;
81 if (!GetValueFromString(aValueAsString,
82 aSVGElement->NumberAttrAllowsPercentage(mAttrEnum),
83 val)) {
84 return NS_ERROR_DOM_SYNTAX_ERR;
87 mBaseVal = val;
88 mIsBaseSet = true;
89 if (!mIsAnimated) {
90 mAnimVal = mBaseVal;
91 } else {
92 aSVGElement->AnimationNeedsResample();
95 // We don't need to call DidChange* here - we're only called by
96 // SVGElement::ParseAttribute under Element::SetAttr,
97 // which takes care of notifying.
98 return NS_OK;
101 void SVGAnimatedNumber::GetBaseValueString(nsAString& aValueAsString) {
102 aValueAsString.Truncate();
103 aValueAsString.AppendFloat(mBaseVal);
106 void SVGAnimatedNumber::SetBaseValue(float aValue, SVGElement* aSVGElement) {
107 if (mIsBaseSet && aValue == mBaseVal) {
108 return;
111 AutoChangeNumberNotifier notifier(this, aSVGElement);
113 mBaseVal = aValue;
114 mIsBaseSet = true;
115 if (!mIsAnimated) {
116 mAnimVal = mBaseVal;
120 void SVGAnimatedNumber::SetAnimValue(float aValue, SVGElement* aSVGElement) {
121 if (mIsAnimated && aValue == mAnimVal) {
122 return;
124 mAnimVal = aValue;
125 mIsAnimated = true;
126 aSVGElement->DidAnimateNumber(mAttrEnum);
129 already_AddRefed<DOMSVGAnimatedNumber> SVGAnimatedNumber::ToDOMAnimatedNumber(
130 SVGElement* aSVGElement) {
131 RefPtr<DOMAnimatedNumber> domAnimatedNumber =
132 sSVGAnimatedNumberTearoffTable.GetTearoff(this);
133 if (!domAnimatedNumber) {
134 domAnimatedNumber = new DOMAnimatedNumber(this, aSVGElement);
135 sSVGAnimatedNumberTearoffTable.AddTearoff(this, domAnimatedNumber);
138 return domAnimatedNumber.forget();
141 SVGAnimatedNumber::DOMAnimatedNumber::~DOMAnimatedNumber() {
142 sSVGAnimatedNumberTearoffTable.RemoveTearoff(mVal);
145 UniquePtr<SMILAttr> SVGAnimatedNumber::ToSMILAttr(SVGElement* aSVGElement) {
146 return MakeUnique<SMILNumber>(this, aSVGElement);
149 nsresult SVGAnimatedNumber::SMILNumber::ValueFromString(
150 const nsAString& aStr,
151 const mozilla::dom::SVGAnimationElement* /*aSrcElement*/, SMILValue& aValue,
152 bool& aPreventCachingOfSandwich) const {
153 float value;
155 if (!GetValueFromString(
156 aStr, mSVGElement->NumberAttrAllowsPercentage(mVal->mAttrEnum),
157 value)) {
158 return NS_ERROR_DOM_SYNTAX_ERR;
161 SMILValue val(SMILFloatType::Singleton());
162 val.mU.mDouble = value;
163 aValue = val;
165 return NS_OK;
168 SMILValue SVGAnimatedNumber::SMILNumber::GetBaseValue() const {
169 SMILValue val(SMILFloatType::Singleton());
170 val.mU.mDouble = mVal->mBaseVal;
171 return val;
174 void SVGAnimatedNumber::SMILNumber::ClearAnimValue() {
175 if (mVal->mIsAnimated) {
176 mVal->mIsAnimated = false;
177 mVal->mAnimVal = mVal->mBaseVal;
178 mSVGElement->DidAnimateNumber(mVal->mAttrEnum);
182 nsresult SVGAnimatedNumber::SMILNumber::SetAnimValue(const SMILValue& aValue) {
183 NS_ASSERTION(aValue.mType == SMILFloatType::Singleton(),
184 "Unexpected type to assign animated value");
185 if (aValue.mType == SMILFloatType::Singleton()) {
186 mVal->SetAnimValue(float(aValue.mU.mDouble), mSVGElement);
188 return NS_OK;
191 } // namespace mozilla