SVGAnimatedEnumeration.cpp (6220B)
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 "SVGAnimatedEnumeration.h" 8 9 #include "SMILEnumType.h" 10 #include "SVGAttrTearoffTable.h" 11 #include "mozilla/SMILValue.h" 12 #include "mozilla/dom/SVGElement.h" 13 #include "nsAtom.h" 14 #include "nsError.h" 15 16 using namespace mozilla::dom; 17 18 namespace mozilla { 19 20 //---------------------------------------------------------------------- 21 // Helper class: AutoChangeEnumNotifier 22 // Stack-based helper class to ensure DidChangeEnum is called. 23 class MOZ_RAII AutoChangeEnumNotifier { 24 public: 25 AutoChangeEnumNotifier(SVGAnimatedEnumeration* aEnum, SVGElement* aSVGElement, 26 bool aDoSetAttr = true) 27 : mEnum(aEnum), mSVGElement(aSVGElement), mDoSetAttr(aDoSetAttr) { 28 MOZ_ASSERT(mEnum, "Expecting non-null enum"); 29 MOZ_ASSERT(mSVGElement, "Expecting non-null element"); 30 } 31 32 ~AutoChangeEnumNotifier() { 33 if (mDoSetAttr) { 34 mSVGElement->DidChangeEnum(mEnum->mAttrEnum); 35 } 36 if (mEnum->mIsAnimated) { 37 mSVGElement->AnimationNeedsResample(); 38 } 39 } 40 41 private: 42 SVGAnimatedEnumeration* const mEnum; 43 SVGElement* const mSVGElement; 44 bool mDoSetAttr; 45 }; 46 47 constinit static SVGAttrTearoffTable<SVGAnimatedEnumeration, 48 SVGAnimatedEnumeration::DOMAnimatedEnum> 49 sSVGAnimatedEnumTearoffTable; 50 51 const SVGEnumMapping* SVGAnimatedEnumeration::GetMapping( 52 SVGElement* aSVGElement) { 53 SVGElement::EnumAttributesInfo info = aSVGElement->GetEnumInfo(); 54 55 NS_ASSERTION(info.mCount > 0 && mAttrEnum < info.mCount, 56 "mapping request for a non-attrib enum"); 57 58 return info.mInfos[mAttrEnum].mMapping; 59 } 60 61 bool SVGAnimatedEnumeration::SetBaseValueAtom(const nsAtom* aValue, 62 SVGElement* aSVGElement) { 63 const SVGEnumMapping* mapping = GetMapping(aSVGElement); 64 65 while (mapping && mapping->mKey) { 66 if (aValue == mapping->mKey) { 67 if (!mIsBaseSet || mBaseVal != mapping->mVal) { 68 mIsBaseSet = true; 69 // We don't need to call DidChange* here - we're only called by 70 // SVGElement::ParseAttribute under Element::SetAttr, 71 // which takes care of notifying. 72 AutoChangeEnumNotifier notifier(this, aSVGElement, false); 73 74 mBaseVal = mapping->mVal; 75 if (!mIsAnimated) { 76 mAnimVal = mBaseVal; 77 } 78 } 79 return true; 80 } 81 mapping++; 82 } 83 84 return false; 85 } 86 87 nsAtom* SVGAnimatedEnumeration::GetBaseValueAtom(SVGElement* aSVGElement) { 88 const SVGEnumMapping* mapping = GetMapping(aSVGElement); 89 90 while (mapping && mapping->mKey) { 91 if (mBaseVal == mapping->mVal) { 92 return mapping->mKey; 93 } 94 mapping++; 95 } 96 NS_ERROR("unknown enumeration value"); 97 return nsGkAtoms::_empty; 98 } 99 100 void SVGAnimatedEnumeration::SetBaseValue(uint16_t aValue, 101 SVGElement* aSVGElement, 102 ErrorResult& aRv) { 103 const SVGEnumMapping* mapping = GetMapping(aSVGElement); 104 105 while (mapping && mapping->mKey) { 106 if (mapping->mVal == aValue) { 107 if (!mIsBaseSet || mBaseVal != uint8_t(aValue)) { 108 mIsBaseSet = true; 109 AutoChangeEnumNotifier notifier(this, aSVGElement); 110 111 mBaseVal = uint8_t(aValue); 112 if (!mIsAnimated) { 113 mAnimVal = mBaseVal; 114 } 115 } 116 return; 117 } 118 mapping++; 119 } 120 return aRv.ThrowTypeError("Invalid SVGAnimatedEnumeration base value"); 121 } 122 123 void SVGAnimatedEnumeration::SetAnimValue(uint16_t aValue, 124 SVGElement* aSVGElement) { 125 if (mIsAnimated && aValue == mAnimVal) { 126 return; 127 } 128 mAnimVal = aValue; 129 mIsAnimated = true; 130 aSVGElement->DidAnimateEnum(mAttrEnum); 131 } 132 133 already_AddRefed<DOMSVGAnimatedEnumeration> 134 SVGAnimatedEnumeration::ToDOMAnimatedEnum(SVGElement* aSVGElement) { 135 RefPtr<DOMAnimatedEnum> domAnimatedEnum = 136 sSVGAnimatedEnumTearoffTable.GetTearoff(this); 137 if (!domAnimatedEnum) { 138 domAnimatedEnum = new DOMAnimatedEnum(this, aSVGElement); 139 sSVGAnimatedEnumTearoffTable.AddTearoff(this, domAnimatedEnum); 140 } 141 142 return domAnimatedEnum.forget(); 143 } 144 145 SVGAnimatedEnumeration::DOMAnimatedEnum::~DOMAnimatedEnum() { 146 sSVGAnimatedEnumTearoffTable.RemoveTearoff(mVal); 147 } 148 149 UniquePtr<SMILAttr> SVGAnimatedEnumeration::ToSMILAttr( 150 SVGElement* aSVGElement) { 151 return MakeUnique<SMILEnum>(this, aSVGElement); 152 } 153 154 nsresult SVGAnimatedEnumeration::SMILEnum::ValueFromString( 155 const nsAString& aStr, const SVGAnimationElement* /*aSrcElement*/, 156 SMILValue& aValue, bool& aPreventCachingOfSandwich) const { 157 nsAtom* valAtom = NS_GetStaticAtom(aStr); 158 if (valAtom) { 159 const SVGEnumMapping* mapping = mVal->GetMapping(mSVGElement); 160 161 while (mapping && mapping->mKey) { 162 if (valAtom == mapping->mKey) { 163 SMILValue val(SMILEnumType::Singleton()); 164 val.mU.mUint = mapping->mVal; 165 aValue = val; 166 return NS_OK; 167 } 168 mapping++; 169 } 170 } 171 172 // only a warning since authors may mistype attribute values 173 NS_WARNING("unknown enumeration key"); 174 return NS_ERROR_FAILURE; 175 } 176 177 SMILValue SVGAnimatedEnumeration::SMILEnum::GetBaseValue() const { 178 SMILValue val(SMILEnumType::Singleton()); 179 val.mU.mUint = mVal->mBaseVal; 180 return val; 181 } 182 183 void SVGAnimatedEnumeration::SMILEnum::ClearAnimValue() { 184 if (mVal->mIsAnimated) { 185 mVal->mIsAnimated = false; 186 mVal->mAnimVal = mVal->mBaseVal; 187 mSVGElement->DidAnimateEnum(mVal->mAttrEnum); 188 } 189 } 190 191 nsresult SVGAnimatedEnumeration::SMILEnum::SetAnimValue( 192 const SMILValue& aValue) { 193 NS_ASSERTION(aValue.mType == SMILEnumType::Singleton(), 194 "Unexpected type to assign animated value"); 195 if (aValue.mType == SMILEnumType::Singleton()) { 196 MOZ_ASSERT(aValue.mU.mUint <= USHRT_MAX, 197 "Very large enumerated value - too big for uint16_t"); 198 mVal->SetAnimValue(uint16_t(aValue.mU.mUint), mSVGElement); 199 } 200 return NS_OK; 201 } 202 203 } // namespace mozilla