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