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 "SVGAnimatedPreserveAspectRatio.h"
8
9 #include "mozAutoDocUpdate.h"
10 #include "mozilla/ArrayUtils.h"
11 #include "mozilla/Maybe.h"
12 #include "mozilla/SMILValue.h"
13 #include "mozilla/SVGContentUtils.h"
14 #include "mozilla/dom/SVGAnimatedPreserveAspectRatioBinding.h"
15 #include "SMILEnumType.h"
16 #include "SVGAttrTearoffTable.h"
17
18 using namespace mozilla::dom;
19
20 namespace mozilla {
21
22 ////////////////////////////////////////////////////////////////////////
23 // SVGAnimatedPreserveAspectRatio class
NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(DOMSVGAnimatedPreserveAspectRatio,mSVGElement)24 NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(
25 DOMSVGAnimatedPreserveAspectRatio, mSVGElement)
26
27 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMSVGAnimatedPreserveAspectRatio, AddRef)
28 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMSVGAnimatedPreserveAspectRatio,
29 Release)
30
31 JSObject* DOMSVGAnimatedPreserveAspectRatio::WrapObject(
32 JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
33 return SVGAnimatedPreserveAspectRatio_Binding::Wrap(aCx, this, aGivenProto);
34 }
35
36 /* Implementation */
37
38 //----------------------------------------------------------------------
39 // Helper class: AutoChangePreserveAspectRatioNotifier
40 // Stack-based helper class to pair calls to WillChangePreserveAspectRatio and
41 // DidChangePreserveAspectRatio.
42 class MOZ_RAII AutoChangePreserveAspectRatioNotifier {
43 public:
AutoChangePreserveAspectRatioNotifier(SVGAnimatedPreserveAspectRatio * aPreserveAspectRatio,SVGElement * aSVGElement,bool aDoSetAttr=true)44 AutoChangePreserveAspectRatioNotifier(
45 SVGAnimatedPreserveAspectRatio* aPreserveAspectRatio,
46 SVGElement* aSVGElement, bool aDoSetAttr = true)
47 : mPreserveAspectRatio(aPreserveAspectRatio),
48 mSVGElement(aSVGElement),
49 mDoSetAttr(aDoSetAttr) {
50 MOZ_ASSERT(mPreserveAspectRatio, "Expecting non-null preserveAspectRatio");
51 MOZ_ASSERT(mSVGElement, "Expecting non-null element");
52 if (mDoSetAttr) {
53 mUpdateBatch.emplace(aSVGElement->GetComposedDoc(), true);
54 mEmptyOrOldValue =
55 mSVGElement->WillChangePreserveAspectRatio(mUpdateBatch.ref());
56 }
57 }
58
~AutoChangePreserveAspectRatioNotifier()59 ~AutoChangePreserveAspectRatioNotifier() {
60 if (mDoSetAttr) {
61 mSVGElement->DidChangePreserveAspectRatio(mEmptyOrOldValue,
62 mUpdateBatch.ref());
63 }
64 if (mPreserveAspectRatio->mIsAnimated) {
65 mSVGElement->AnimationNeedsResample();
66 }
67 }
68
69 private:
70 SVGAnimatedPreserveAspectRatio* const mPreserveAspectRatio;
71 SVGElement* const mSVGElement;
72 Maybe<mozAutoDocUpdate> mUpdateBatch;
73 nsAttrValue mEmptyOrOldValue;
74 bool mDoSetAttr;
75 };
76
77 static SVGAttrTearoffTable<SVGAnimatedPreserveAspectRatio,
78 DOMSVGAnimatedPreserveAspectRatio>
79 sSVGAnimatedPAspectRatioTearoffTable;
80 static SVGAttrTearoffTable<SVGAnimatedPreserveAspectRatio,
81 DOMSVGPreserveAspectRatio>
82 sBaseSVGPAspectRatioTearoffTable;
83 static SVGAttrTearoffTable<SVGAnimatedPreserveAspectRatio,
84 DOMSVGPreserveAspectRatio>
85 sAnimSVGPAspectRatioTearoffTable;
86
87 already_AddRefed<DOMSVGPreserveAspectRatio>
BaseVal()88 DOMSVGAnimatedPreserveAspectRatio::BaseVal() {
89 RefPtr<DOMSVGPreserveAspectRatio> domBaseVal =
90 sBaseSVGPAspectRatioTearoffTable.GetTearoff(mVal);
91 if (!domBaseVal) {
92 domBaseVal = new DOMSVGPreserveAspectRatio(mVal, mSVGElement, true);
93 sBaseSVGPAspectRatioTearoffTable.AddTearoff(mVal, domBaseVal);
94 }
95
96 return domBaseVal.forget();
97 }
98
~DOMSVGPreserveAspectRatio()99 DOMSVGPreserveAspectRatio::~DOMSVGPreserveAspectRatio() {
100 if (mIsBaseValue) {
101 sBaseSVGPAspectRatioTearoffTable.RemoveTearoff(mVal);
102 } else {
103 sAnimSVGPAspectRatioTearoffTable.RemoveTearoff(mVal);
104 }
105 }
106
107 already_AddRefed<DOMSVGPreserveAspectRatio>
AnimVal()108 DOMSVGAnimatedPreserveAspectRatio::AnimVal() {
109 RefPtr<DOMSVGPreserveAspectRatio> domAnimVal =
110 sAnimSVGPAspectRatioTearoffTable.GetTearoff(mVal);
111 if (!domAnimVal) {
112 domAnimVal = new DOMSVGPreserveAspectRatio(mVal, mSVGElement, false);
113 sAnimSVGPAspectRatioTearoffTable.AddTearoff(mVal, domAnimVal);
114 }
115
116 return domAnimVal.forget();
117 }
118
SetBaseValueString(const nsAString & aValueAsString,SVGElement * aSVGElement,bool aDoSetAttr)119 nsresult SVGAnimatedPreserveAspectRatio::SetBaseValueString(
120 const nsAString& aValueAsString, SVGElement* aSVGElement, bool aDoSetAttr) {
121 SVGPreserveAspectRatio val;
122 nsresult res = SVGPreserveAspectRatio::FromString(aValueAsString, &val);
123 if (NS_FAILED(res)) {
124 return res;
125 }
126
127 AutoChangePreserveAspectRatioNotifier notifier(this, aSVGElement, aDoSetAttr);
128
129 mBaseVal = val;
130 mIsBaseSet = true;
131 if (!mIsAnimated) {
132 mAnimVal = mBaseVal;
133 }
134
135 return NS_OK;
136 }
137
GetBaseValueString(nsAString & aValueAsString) const138 void SVGAnimatedPreserveAspectRatio::GetBaseValueString(
139 nsAString& aValueAsString) const {
140 mBaseVal.ToString(aValueAsString);
141 }
142
SetBaseValue(const SVGPreserveAspectRatio & aValue,SVGElement * aSVGElement)143 void SVGAnimatedPreserveAspectRatio::SetBaseValue(
144 const SVGPreserveAspectRatio& aValue, SVGElement* aSVGElement) {
145 if (mIsBaseSet && mBaseVal == aValue) {
146 return;
147 }
148
149 AutoChangePreserveAspectRatioNotifier notifier(this, aSVGElement);
150
151 mBaseVal = aValue;
152 mIsBaseSet = true;
153 if (!mIsAnimated) {
154 mAnimVal = mBaseVal;
155 }
156 }
157
PackPreserveAspectRatio(const SVGPreserveAspectRatio & par)158 static uint64_t PackPreserveAspectRatio(const SVGPreserveAspectRatio& par) {
159 // All preserveAspectRatio values are enum values (do not interpolate), so we
160 // can safely collate them and treat them as a single enum as for SMIL.
161 uint64_t packed = 0;
162 packed |= uint64_t(par.GetAlign()) << 8;
163 packed |= uint64_t(par.GetMeetOrSlice());
164 return packed;
165 }
166
SetAnimValue(uint64_t aPackedValue,SVGElement * aSVGElement)167 void SVGAnimatedPreserveAspectRatio::SetAnimValue(uint64_t aPackedValue,
168 SVGElement* aSVGElement) {
169 if (mIsAnimated && PackPreserveAspectRatio(mAnimVal) == aPackedValue) {
170 return;
171 }
172 mAnimVal.SetAlign(uint16_t((aPackedValue & 0xff00) >> 8));
173 mAnimVal.SetMeetOrSlice(uint16_t(aPackedValue & 0xff));
174 mIsAnimated = true;
175 aSVGElement->DidAnimatePreserveAspectRatio();
176 }
177
178 already_AddRefed<DOMSVGAnimatedPreserveAspectRatio>
ToDOMAnimatedPreserveAspectRatio(SVGElement * aSVGElement)179 SVGAnimatedPreserveAspectRatio::ToDOMAnimatedPreserveAspectRatio(
180 SVGElement* aSVGElement) {
181 RefPtr<DOMSVGAnimatedPreserveAspectRatio> domAnimatedPAspectRatio =
182 sSVGAnimatedPAspectRatioTearoffTable.GetTearoff(this);
183 if (!domAnimatedPAspectRatio) {
184 domAnimatedPAspectRatio =
185 new DOMSVGAnimatedPreserveAspectRatio(this, aSVGElement);
186 sSVGAnimatedPAspectRatioTearoffTable.AddTearoff(this,
187 domAnimatedPAspectRatio);
188 }
189 return domAnimatedPAspectRatio.forget();
190 }
191
~DOMSVGAnimatedPreserveAspectRatio()192 DOMSVGAnimatedPreserveAspectRatio::~DOMSVGAnimatedPreserveAspectRatio() {
193 sSVGAnimatedPAspectRatioTearoffTable.RemoveTearoff(mVal);
194 }
195
ToSMILAttr(SVGElement * aSVGElement)196 UniquePtr<SMILAttr> SVGAnimatedPreserveAspectRatio::ToSMILAttr(
197 SVGElement* aSVGElement) {
198 return MakeUnique<SMILPreserveAspectRatio>(this, aSVGElement);
199 }
200
201 // typedef for inner class, to make function signatures shorter below:
202 using SMILPreserveAspectRatio =
203 SVGAnimatedPreserveAspectRatio::SMILPreserveAspectRatio;
204
ValueFromString(const nsAString & aStr,const SVGAnimationElement *,SMILValue & aValue,bool & aPreventCachingOfSandwich) const205 nsresult SMILPreserveAspectRatio::ValueFromString(
206 const nsAString& aStr, const SVGAnimationElement* /*aSrcElement*/,
207 SMILValue& aValue, bool& aPreventCachingOfSandwich) const {
208 SVGPreserveAspectRatio par;
209 nsresult res = SVGPreserveAspectRatio::FromString(aStr, &par);
210 NS_ENSURE_SUCCESS(res, res);
211
212 SMILValue val(SMILEnumType::Singleton());
213 val.mU.mUint = PackPreserveAspectRatio(par);
214 aValue = val;
215 aPreventCachingOfSandwich = false;
216 return NS_OK;
217 }
218
GetBaseValue() const219 SMILValue SMILPreserveAspectRatio::GetBaseValue() const {
220 SMILValue val(SMILEnumType::Singleton());
221 val.mU.mUint = PackPreserveAspectRatio(mVal->GetBaseValue());
222 return val;
223 }
224
ClearAnimValue()225 void SMILPreserveAspectRatio::ClearAnimValue() {
226 if (mVal->mIsAnimated) {
227 mVal->mIsAnimated = false;
228 mVal->mAnimVal = mVal->mBaseVal;
229 mSVGElement->DidAnimatePreserveAspectRatio();
230 }
231 }
232
SetAnimValue(const SMILValue & aValue)233 nsresult SMILPreserveAspectRatio::SetAnimValue(const SMILValue& aValue) {
234 NS_ASSERTION(aValue.mType == SMILEnumType::Singleton(),
235 "Unexpected type to assign animated value");
236 if (aValue.mType == SMILEnumType::Singleton()) {
237 mVal->SetAnimValue(aValue.mU.mUint, mSVGElement);
238 }
239 return NS_OK;
240 }
241
242 } // namespace mozilla
243