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 "nsSVGNumber2.h"
8 #include "mozilla/Attributes.h"
9 #include "nsContentUtils.h" // NS_ENSURE_FINITE
10 #include "nsSMILFloatType.h"
11 #include "nsSMILValue.h"
12 #include "nsSVGAttrTearoffTable.h"
13 #include "SVGContentUtils.h"
14
15 using namespace mozilla;
16 using namespace mozilla::dom;
17
18 /* Implementation */
19
20 static nsSVGAttrTearoffTable<nsSVGNumber2, nsSVGNumber2::DOMAnimatedNumber>
21 sSVGAnimatedNumberTearoffTable;
22
GetValueFromString(const nsAString & aString,bool aPercentagesAllowed,float & aValue)23 static bool GetValueFromString(const nsAString& aString,
24 bool aPercentagesAllowed, float& aValue) {
25 RangedPtr<const char16_t> iter = SVGContentUtils::GetStartRangedPtr(aString);
26 const RangedPtr<const char16_t> end =
27 SVGContentUtils::GetEndRangedPtr(aString);
28
29 if (!SVGContentUtils::ParseNumber(iter, end, aValue)) {
30 return false;
31 }
32
33 if (aPercentagesAllowed) {
34 const nsAString& units = Substring(iter.get(), end.get());
35 if (units.EqualsLiteral("%")) {
36 aValue /= 100;
37 return true;
38 }
39 }
40
41 return iter == end;
42 }
43
SetBaseValueString(const nsAString & aValueAsString,nsSVGElement * aSVGElement)44 nsresult nsSVGNumber2::SetBaseValueString(const nsAString& aValueAsString,
45 nsSVGElement* aSVGElement) {
46 float val;
47
48 if (!GetValueFromString(aValueAsString,
49 aSVGElement->NumberAttrAllowsPercentage(mAttrEnum),
50 val)) {
51 return NS_ERROR_DOM_SYNTAX_ERR;
52 }
53
54 mBaseVal = val;
55 mIsBaseSet = true;
56 if (!mIsAnimated) {
57 mAnimVal = mBaseVal;
58 } else {
59 aSVGElement->AnimationNeedsResample();
60 }
61
62 // We don't need to call DidChange* here - we're only called by
63 // nsSVGElement::ParseAttribute under Element::SetAttr,
64 // which takes care of notifying.
65 return NS_OK;
66 }
67
GetBaseValueString(nsAString & aValueAsString)68 void nsSVGNumber2::GetBaseValueString(nsAString& aValueAsString) {
69 aValueAsString.Truncate();
70 aValueAsString.AppendFloat(mBaseVal);
71 }
72
SetBaseValue(float aValue,nsSVGElement * aSVGElement)73 void nsSVGNumber2::SetBaseValue(float aValue, nsSVGElement* aSVGElement) {
74 if (mIsBaseSet && aValue == mBaseVal) {
75 return;
76 }
77
78 mBaseVal = aValue;
79 mIsBaseSet = true;
80 if (!mIsAnimated) {
81 mAnimVal = mBaseVal;
82 } else {
83 aSVGElement->AnimationNeedsResample();
84 }
85 aSVGElement->DidChangeNumber(mAttrEnum);
86 }
87
SetAnimValue(float aValue,nsSVGElement * aSVGElement)88 void nsSVGNumber2::SetAnimValue(float aValue, nsSVGElement* aSVGElement) {
89 if (mIsAnimated && aValue == mAnimVal) {
90 return;
91 }
92 mAnimVal = aValue;
93 mIsAnimated = true;
94 aSVGElement->DidAnimateNumber(mAttrEnum);
95 }
96
ToDOMAnimatedNumber(nsSVGElement * aSVGElement)97 already_AddRefed<SVGAnimatedNumber> nsSVGNumber2::ToDOMAnimatedNumber(
98 nsSVGElement* aSVGElement) {
99 RefPtr<DOMAnimatedNumber> domAnimatedNumber =
100 sSVGAnimatedNumberTearoffTable.GetTearoff(this);
101 if (!domAnimatedNumber) {
102 domAnimatedNumber = new DOMAnimatedNumber(this, aSVGElement);
103 sSVGAnimatedNumberTearoffTable.AddTearoff(this, domAnimatedNumber);
104 }
105
106 return domAnimatedNumber.forget();
107 }
108
~DOMAnimatedNumber()109 nsSVGNumber2::DOMAnimatedNumber::~DOMAnimatedNumber() {
110 sSVGAnimatedNumberTearoffTable.RemoveTearoff(mVal);
111 }
112
ToSMILAttr(nsSVGElement * aSVGElement)113 UniquePtr<nsISMILAttr> nsSVGNumber2::ToSMILAttr(nsSVGElement* aSVGElement) {
114 return MakeUnique<SMILNumber>(this, aSVGElement);
115 }
116
ValueFromString(const nsAString & aStr,const mozilla::dom::SVGAnimationElement *,nsSMILValue & aValue,bool & aPreventCachingOfSandwich) const117 nsresult nsSVGNumber2::SMILNumber::ValueFromString(
118 const nsAString& aStr,
119 const mozilla::dom::SVGAnimationElement* /*aSrcElement*/,
120 nsSMILValue& aValue, bool& aPreventCachingOfSandwich) const {
121 float value;
122
123 if (!GetValueFromString(
124 aStr, mSVGElement->NumberAttrAllowsPercentage(mVal->mAttrEnum),
125 value)) {
126 return NS_ERROR_DOM_SYNTAX_ERR;
127 }
128
129 nsSMILValue val(nsSMILFloatType::Singleton());
130 val.mU.mDouble = value;
131 aValue = val;
132 aPreventCachingOfSandwich = false;
133
134 return NS_OK;
135 }
136
GetBaseValue() const137 nsSMILValue nsSVGNumber2::SMILNumber::GetBaseValue() const {
138 nsSMILValue val(nsSMILFloatType::Singleton());
139 val.mU.mDouble = mVal->mBaseVal;
140 return val;
141 }
142
ClearAnimValue()143 void nsSVGNumber2::SMILNumber::ClearAnimValue() {
144 if (mVal->mIsAnimated) {
145 mVal->mIsAnimated = false;
146 mVal->mAnimVal = mVal->mBaseVal;
147 mSVGElement->DidAnimateNumber(mVal->mAttrEnum);
148 }
149 }
150
SetAnimValue(const nsSMILValue & aValue)151 nsresult nsSVGNumber2::SMILNumber::SetAnimValue(const nsSMILValue& aValue) {
152 NS_ASSERTION(aValue.mType == nsSMILFloatType::Singleton(),
153 "Unexpected type to assign animated value");
154 if (aValue.mType == nsSMILFloatType::Singleton()) {
155 mVal->SetAnimValue(float(aValue.mU.mDouble), mSVGElement);
156 }
157 return NS_OK;
158 }
159