Merge mozilla-central to autoland on a CLOSED TREE
[gecko.git] / dom / svg / SVGAnimatedNumber.cpp
blobf8a56f9e26b6616153859cbf4c686103b968220b
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 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 RangedPtr<const char16_t> iter = SVGContentUtils::GetStartRangedPtr(token);
59 const RangedPtr<const char16_t> end = SVGContentUtils::GetEndRangedPtr(token);
61 if (!SVGContentUtils::ParseNumber(iter, end, aValue)) {
62 return false;
65 if (aPercentagesAllowed) {
66 const nsAString& units = Substring(iter.get(), end.get());
67 if (units.EqualsLiteral("%")) {
68 aValue /= 100;
69 return true;
73 return iter == end;
76 nsresult SVGAnimatedNumber::SetBaseValueString(const nsAString& aValueAsString,
77 SVGElement* aSVGElement) {
78 float val;
80 if (!GetValueFromString(aValueAsString,
81 aSVGElement->NumberAttrAllowsPercentage(mAttrEnum),
82 val)) {
83 return NS_ERROR_DOM_SYNTAX_ERR;
86 mBaseVal = val;
87 mIsBaseSet = true;
88 if (!mIsAnimated) {
89 mAnimVal = mBaseVal;
90 } else {
91 aSVGElement->AnimationNeedsResample();
94 // We don't need to call DidChange* here - we're only called by
95 // SVGElement::ParseAttribute under Element::SetAttr,
96 // which takes care of notifying.
97 return NS_OK;
100 void SVGAnimatedNumber::GetBaseValueString(nsAString& aValueAsString) {
101 aValueAsString.Truncate();
102 aValueAsString.AppendFloat(mBaseVal);
105 void SVGAnimatedNumber::SetBaseValue(float aValue, SVGElement* aSVGElement) {
106 if (mIsBaseSet && aValue == mBaseVal) {
107 return;
110 AutoChangeNumberNotifier notifier(this, aSVGElement);
112 mBaseVal = aValue;
113 mIsBaseSet = true;
114 if (!mIsAnimated) {
115 mAnimVal = mBaseVal;
119 void SVGAnimatedNumber::SetAnimValue(float aValue, SVGElement* aSVGElement) {
120 if (mIsAnimated && aValue == mAnimVal) {
121 return;
123 mAnimVal = aValue;
124 mIsAnimated = true;
125 aSVGElement->DidAnimateNumber(mAttrEnum);
128 already_AddRefed<DOMSVGAnimatedNumber> SVGAnimatedNumber::ToDOMAnimatedNumber(
129 SVGElement* aSVGElement) {
130 RefPtr<DOMAnimatedNumber> domAnimatedNumber =
131 sSVGAnimatedNumberTearoffTable.GetTearoff(this);
132 if (!domAnimatedNumber) {
133 domAnimatedNumber = new DOMAnimatedNumber(this, aSVGElement);
134 sSVGAnimatedNumberTearoffTable.AddTearoff(this, domAnimatedNumber);
137 return domAnimatedNumber.forget();
140 SVGAnimatedNumber::DOMAnimatedNumber::~DOMAnimatedNumber() {
141 sSVGAnimatedNumberTearoffTable.RemoveTearoff(mVal);
144 UniquePtr<SMILAttr> SVGAnimatedNumber::ToSMILAttr(SVGElement* aSVGElement) {
145 return MakeUnique<SMILNumber>(this, aSVGElement);
148 nsresult SVGAnimatedNumber::SMILNumber::ValueFromString(
149 const nsAString& aStr,
150 const mozilla::dom::SVGAnimationElement* /*aSrcElement*/, SMILValue& aValue,
151 bool& aPreventCachingOfSandwich) const {
152 float value;
154 if (!GetValueFromString(
155 aStr, mSVGElement->NumberAttrAllowsPercentage(mVal->mAttrEnum),
156 value)) {
157 return NS_ERROR_DOM_SYNTAX_ERR;
160 SMILValue val(SMILFloatType::Singleton());
161 val.mU.mDouble = value;
162 aValue = val;
164 return NS_OK;
167 SMILValue SVGAnimatedNumber::SMILNumber::GetBaseValue() const {
168 SMILValue val(SMILFloatType::Singleton());
169 val.mU.mDouble = mVal->mBaseVal;
170 return val;
173 void SVGAnimatedNumber::SMILNumber::ClearAnimValue() {
174 if (mVal->mIsAnimated) {
175 mVal->mIsAnimated = false;
176 mVal->mAnimVal = mVal->mBaseVal;
177 mSVGElement->DidAnimateNumber(mVal->mAttrEnum);
181 nsresult SVGAnimatedNumber::SMILNumber::SetAnimValue(const SMILValue& aValue) {
182 NS_ASSERTION(aValue.mType == SMILFloatType::Singleton(),
183 "Unexpected type to assign animated value");
184 if (aValue.mType == SMILFloatType::Singleton()) {
185 mVal->SetAnimValue(float(aValue.mU.mDouble), mSVGElement);
187 return NS_OK;
190 } // namespace mozilla