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