SVGAnimatedInteger.cpp (5058B)
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 "SVGAnimatedInteger.h" 8 9 #include "SMILIntegerType.h" 10 #include "SVGAttrTearoffTable.h" 11 #include "mozilla/SMILValue.h" 12 #include "mozilla/SVGContentUtils.h" 13 #include "nsError.h" 14 15 using namespace mozilla::dom; 16 17 namespace mozilla { 18 19 /* Implementation */ 20 21 //---------------------------------------------------------------------- 22 // Helper class: AutoChangeIntegerNotifier 23 // Stack-based helper class ensure DidChangeInteger is called. 24 class MOZ_RAII AutoChangeIntegerNotifier { 25 public: 26 AutoChangeIntegerNotifier(SVGAnimatedInteger* aInteger, 27 SVGElement* aSVGElement, bool aDoSetAttr = true) 28 : mInteger(aInteger), mSVGElement(aSVGElement), mDoSetAttr(aDoSetAttr) { 29 MOZ_ASSERT(mInteger, "Expecting non-null integer"); 30 MOZ_ASSERT(mSVGElement, "Expecting non-null element"); 31 } 32 33 ~AutoChangeIntegerNotifier() { 34 if (mDoSetAttr) { 35 mSVGElement->DidChangeInteger(mInteger->mAttrEnum); 36 } 37 if (mInteger->mIsAnimated) { 38 mSVGElement->AnimationNeedsResample(); 39 } 40 } 41 42 private: 43 SVGAnimatedInteger* const mInteger; 44 SVGElement* const mSVGElement; 45 bool mDoSetAttr; 46 }; 47 48 constinit static SVGAttrTearoffTable<SVGAnimatedInteger, 49 SVGAnimatedInteger::DOMAnimatedInteger> 50 sSVGAnimatedIntegerTearoffTable; 51 52 nsresult SVGAnimatedInteger::SetBaseValueString(const nsAString& aValueAsString, 53 SVGElement* aSVGElement) { 54 bool success; 55 auto token = SVGContentUtils::GetAndEnsureOneToken(aValueAsString, success); 56 57 if (!success) { 58 return NS_ERROR_DOM_SYNTAX_ERR; 59 } 60 61 int32_t value; 62 63 if (!SVGContentUtils::ParseInteger(token, value)) { 64 return NS_ERROR_DOM_SYNTAX_ERR; 65 } 66 67 AutoChangeIntegerNotifier notifier(this, aSVGElement, false); 68 69 mIsBaseSet = true; 70 mBaseVal = value; 71 if (!mIsAnimated) { 72 mAnimVal = mBaseVal; 73 } 74 return NS_OK; 75 } 76 77 void SVGAnimatedInteger::GetBaseValueString(nsAString& aValueAsString) { 78 aValueAsString.Truncate(); 79 aValueAsString.AppendInt(mBaseVal); 80 } 81 82 void SVGAnimatedInteger::SetBaseValue(int aValue, SVGElement* aSVGElement) { 83 // We can't just rely on SetParsedAttrValue (as called by DidChangeInteger) 84 // detecting redundant changes since it will compare false if the existing 85 // attribute value has an associated serialized version (a string value) even 86 // if the integers match due to the way integers are stored in nsAttrValue. 87 if (aValue == mBaseVal && mIsBaseSet) { 88 return; 89 } 90 91 AutoChangeIntegerNotifier notifier(this, aSVGElement); 92 93 mBaseVal = aValue; 94 mIsBaseSet = true; 95 if (!mIsAnimated) { 96 mAnimVal = mBaseVal; 97 } 98 } 99 100 void SVGAnimatedInteger::SetAnimValue(int aValue, SVGElement* aSVGElement) { 101 if (mIsAnimated && aValue == mAnimVal) { 102 return; 103 } 104 mAnimVal = aValue; 105 mIsAnimated = true; 106 aSVGElement->DidAnimateInteger(mAttrEnum); 107 } 108 109 already_AddRefed<DOMSVGAnimatedInteger> 110 SVGAnimatedInteger::ToDOMAnimatedInteger(SVGElement* aSVGElement) { 111 RefPtr<DOMAnimatedInteger> domAnimatedInteger = 112 sSVGAnimatedIntegerTearoffTable.GetTearoff(this); 113 if (!domAnimatedInteger) { 114 domAnimatedInteger = new DOMAnimatedInteger(this, aSVGElement); 115 sSVGAnimatedIntegerTearoffTable.AddTearoff(this, domAnimatedInteger); 116 } 117 118 return domAnimatedInteger.forget(); 119 } 120 121 SVGAnimatedInteger::DOMAnimatedInteger::~DOMAnimatedInteger() { 122 sSVGAnimatedIntegerTearoffTable.RemoveTearoff(mVal); 123 } 124 125 UniquePtr<SMILAttr> SVGAnimatedInteger::ToSMILAttr(SVGElement* aSVGElement) { 126 return MakeUnique<SMILInteger>(this, aSVGElement); 127 } 128 129 nsresult SVGAnimatedInteger::SMILInteger::ValueFromString( 130 const nsAString& aStr, const dom::SVGAnimationElement* /*aSrcElement*/, 131 SMILValue& aValue, bool& aPreventCachingOfSandwich) const { 132 int32_t val; 133 134 if (!SVGContentUtils::ParseInteger(aStr, val)) { 135 return NS_ERROR_DOM_SYNTAX_ERR; 136 } 137 138 SMILValue smilVal(SMILIntegerType::Singleton()); 139 smilVal.mU.mInt = val; 140 aValue = smilVal; 141 return NS_OK; 142 } 143 144 SMILValue SVGAnimatedInteger::SMILInteger::GetBaseValue() const { 145 SMILValue val(SMILIntegerType::Singleton()); 146 val.mU.mInt = mVal->mBaseVal; 147 return val; 148 } 149 150 void SVGAnimatedInteger::SMILInteger::ClearAnimValue() { 151 if (mVal->mIsAnimated) { 152 mVal->mIsAnimated = false; 153 mVal->mAnimVal = mVal->mBaseVal; 154 mSVGElement->DidAnimateInteger(mVal->mAttrEnum); 155 } 156 } 157 158 nsresult SVGAnimatedInteger::SMILInteger::SetAnimValue( 159 const SMILValue& aValue) { 160 NS_ASSERTION(aValue.mType == SMILIntegerType::Singleton(), 161 "Unexpected type to assign animated value"); 162 if (aValue.mType == SMILIntegerType::Singleton()) { 163 mVal->SetAnimValue(int(aValue.mU.mInt), mSVGElement); 164 } 165 return NS_OK; 166 } 167 168 } // namespace mozilla