SVGAnimatedBoolean.cpp (5215B)
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 "SVGAnimatedBoolean.h" 8 9 #include "DOMSVGAnimatedBoolean.h" 10 #include "SMILBoolType.h" 11 #include "SVGAttrTearoffTable.h" 12 #include "mozilla/SMILValue.h" 13 #include "nsError.h" 14 15 using namespace mozilla::dom; 16 17 namespace mozilla { 18 19 /* Implementation */ 20 21 //---------------------------------------------------------------------- 22 // Helper class: AutoChangeBooleanNotifier 23 // Stack-based helper class to ensure DidChangeBoolean is called. 24 class MOZ_RAII AutoChangeBooleanNotifier { 25 public: 26 AutoChangeBooleanNotifier(SVGAnimatedBoolean* aBoolean, 27 SVGElement* aSVGElement, bool aDoSetAttr = true) 28 : mBoolean(aBoolean), mSVGElement(aSVGElement), mDoSetAttr(aDoSetAttr) { 29 MOZ_ASSERT(mBoolean, "Expecting non-null boolean"); 30 MOZ_ASSERT(mSVGElement, "Expecting non-null element"); 31 } 32 33 ~AutoChangeBooleanNotifier() { 34 if (mDoSetAttr) { 35 mSVGElement->DidChangeBoolean(mBoolean->mAttrEnum); 36 } 37 if (mBoolean->mIsAnimated) { 38 mSVGElement->AnimationNeedsResample(); 39 } 40 } 41 42 private: 43 SVGAnimatedBoolean* const mBoolean; 44 SVGElement* const mSVGElement; 45 bool mDoSetAttr; 46 }; 47 48 static inline SVGAttrTearoffTable<SVGAnimatedBoolean, DOMSVGAnimatedBoolean>& 49 SVGAnimatedBooleanTearoffTable() { 50 static SVGAttrTearoffTable<SVGAnimatedBoolean, DOMSVGAnimatedBoolean> 51 sSVGAnimatedBooleanTearoffTable; 52 return sSVGAnimatedBooleanTearoffTable; 53 } 54 55 static bool GetValueFromString(const nsAString& aValueAsString, bool& aValue) { 56 if (aValueAsString.EqualsLiteral("true")) { 57 aValue = true; 58 return true; 59 } 60 if (aValueAsString.EqualsLiteral("false")) { 61 aValue = false; 62 return true; 63 } 64 return false; 65 } 66 67 static bool GetValueFromAtom(const nsAtom* aValueAsAtom, bool* aValue) { 68 if (aValueAsAtom == nsGkAtoms::_true) { 69 *aValue = true; 70 return true; 71 } 72 if (aValueAsAtom == nsGkAtoms::_false) { 73 *aValue = false; 74 return true; 75 } 76 return false; 77 } 78 79 nsresult SVGAnimatedBoolean::SetBaseValueAtom(const nsAtom* aValue, 80 SVGElement* aSVGElement) { 81 bool val = false; 82 83 if (!GetValueFromAtom(aValue, &val)) { 84 return NS_ERROR_DOM_SYNTAX_ERR; 85 } 86 87 // We don't need to call DidChange* here - we're only called by 88 // SVGElement::ParseAttribute under Element::SetAttr, 89 // which takes care of notifying. 90 AutoChangeBooleanNotifier notifier(this, aSVGElement, false); 91 92 mBaseVal = val; 93 if (!mIsAnimated) { 94 mAnimVal = mBaseVal; 95 } 96 97 return NS_OK; 98 } 99 100 nsAtom* SVGAnimatedBoolean::GetBaseValueAtom() const { 101 return mBaseVal ? nsGkAtoms::_true : nsGkAtoms::_false; 102 } 103 104 void SVGAnimatedBoolean::SetBaseValue(bool aValue, SVGElement* aSVGElement) { 105 if (aValue == mBaseVal) { 106 return; 107 } 108 109 AutoChangeBooleanNotifier notifier(this, aSVGElement); 110 111 mBaseVal = aValue; 112 if (!mIsAnimated) { 113 mAnimVal = mBaseVal; 114 } 115 } 116 117 void SVGAnimatedBoolean::SetAnimValue(bool aValue, SVGElement* aSVGElement) { 118 if (mIsAnimated && mAnimVal == aValue) { 119 return; 120 } 121 mAnimVal = aValue; 122 mIsAnimated = true; 123 aSVGElement->DidAnimateBoolean(mAttrEnum); 124 } 125 126 already_AddRefed<DOMSVGAnimatedBoolean> 127 SVGAnimatedBoolean::ToDOMAnimatedBoolean(SVGElement* aSVGElement) { 128 RefPtr<DOMSVGAnimatedBoolean> domAnimatedBoolean = 129 SVGAnimatedBooleanTearoffTable().GetTearoff(this); 130 if (!domAnimatedBoolean) { 131 domAnimatedBoolean = new DOMSVGAnimatedBoolean(this, aSVGElement); 132 SVGAnimatedBooleanTearoffTable().AddTearoff(this, domAnimatedBoolean); 133 } 134 135 return domAnimatedBoolean.forget(); 136 } 137 138 DOMSVGAnimatedBoolean::~DOMSVGAnimatedBoolean() { 139 SVGAnimatedBooleanTearoffTable().RemoveTearoff(mVal); 140 } 141 142 UniquePtr<SMILAttr> SVGAnimatedBoolean::ToSMILAttr(SVGElement* aSVGElement) { 143 return MakeUnique<SMILBool>(this, aSVGElement); 144 } 145 146 nsresult SVGAnimatedBoolean::SMILBool::ValueFromString( 147 const nsAString& aStr, const SVGAnimationElement* /*aSrcElement*/, 148 SMILValue& aValue, bool& aPreventCachingOfSandwich) const { 149 bool value; 150 if (!GetValueFromString(aStr, value)) { 151 return NS_ERROR_DOM_SYNTAX_ERR; 152 } 153 154 SMILValue val(SMILBoolType::Singleton()); 155 val.mU.mBool = value; 156 aValue = val; 157 158 return NS_OK; 159 } 160 161 SMILValue SVGAnimatedBoolean::SMILBool::GetBaseValue() const { 162 SMILValue val(SMILBoolType::Singleton()); 163 val.mU.mBool = mVal->mBaseVal; 164 return val; 165 } 166 167 void SVGAnimatedBoolean::SMILBool::ClearAnimValue() { 168 if (mVal->mIsAnimated) { 169 mVal->mIsAnimated = false; 170 mVal->mAnimVal = mVal->mBaseVal; 171 mSVGElement->DidAnimateBoolean(mVal->mAttrEnum); 172 } 173 } 174 175 nsresult SVGAnimatedBoolean::SMILBool::SetAnimValue(const SMILValue& aValue) { 176 NS_ASSERTION(aValue.mType == SMILBoolType::Singleton(), 177 "Unexpected type to assign animated value"); 178 if (aValue.mType == SMILBoolType::Singleton()) { 179 mVal->SetAnimValue(uint16_t(aValue.mU.mBool), mSVGElement); 180 } 181 return NS_OK; 182 } 183 184 } // namespace mozilla