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