SVGAnimatedNumberList.cpp (6352B)
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 "SVGAnimatedNumberList.h" 8 9 #include <utility> 10 11 #include "DOMSVGAnimatedNumberList.h" 12 #include "SVGNumberListSMILType.h" 13 #include "mozilla/SMILValue.h" 14 #include "mozilla/Try.h" 15 #include "mozilla/dom/SVGElement.h" 16 17 using namespace mozilla::dom; 18 19 namespace mozilla { 20 21 nsresult SVGAnimatedNumberList::SetBaseValueString(const nsAString& aValue) { 22 SVGNumberList newBaseValue; 23 MOZ_TRY(newBaseValue.SetValueFromString(aValue)); 24 25 DOMSVGAnimatedNumberList* domWrapper = 26 DOMSVGAnimatedNumberList::GetDOMWrapperIfExists(this); 27 if (domWrapper) { 28 // We must send this notification *before* changing mBaseVal! If the length 29 // of our baseVal is being reduced, our baseVal's DOM wrapper list may have 30 // to remove DOM items from itself, and any removed DOM items need to copy 31 // their internal counterpart values *before* we change them. 32 // 33 domWrapper->InternalBaseValListWillChangeTo(newBaseValue); 34 } 35 36 // We don't need to call DidChange* here - we're only called by 37 // SVGElement::ParseAttribute under Element::SetAttr, 38 // which takes care of notifying. 39 40 mIsBaseSet = true; 41 mBaseVal.SwapWith(newBaseValue); 42 return NS_OK; 43 } 44 45 void SVGAnimatedNumberList::ClearBaseValue(uint32_t aAttrEnum) { 46 DOMSVGAnimatedNumberList* domWrapper = 47 DOMSVGAnimatedNumberList::GetDOMWrapperIfExists(this); 48 if (domWrapper) { 49 // We must send this notification *before* changing mBaseVal! (See above.) 50 domWrapper->InternalBaseValListWillChangeTo(SVGNumberList()); 51 } 52 mBaseVal.Clear(); 53 mIsBaseSet = false; 54 // Caller notifies 55 } 56 57 nsresult SVGAnimatedNumberList::SetAnimValue(const SVGNumberList& aNewAnimValue, 58 SVGElement* aElement, 59 uint32_t aAttrEnum) { 60 DOMSVGAnimatedNumberList* domWrapper = 61 DOMSVGAnimatedNumberList::GetDOMWrapperIfExists(this); 62 if (domWrapper) { 63 // A new animation may totally change the number of items in the animVal 64 // list, replacing what was essentially a mirror of the baseVal list, or 65 // else replacing and overriding an existing animation. When this happens 66 // we must try and keep our animVal's DOM wrapper in sync (see the comment 67 // in DOMSVGAnimatedNumberList::InternalBaseValListWillChangeTo). 68 // 69 // It's not possible for us to reliably distinguish between calls to this 70 // method that are setting a new sample for an existing animation, and 71 // calls that are setting the first sample of an animation that will 72 // override an existing animation. Happily it's cheap to just blindly 73 // notify our animVal's DOM wrapper of its internal counterpart's new value 74 // each time this method is called, so that's what we do. 75 // 76 // Note that we must send this notification *before* setting or changing 77 // mAnimVal! (See the comment in SetBaseValueString above.) 78 // 79 domWrapper->InternalAnimValListWillChangeTo(aNewAnimValue); 80 } 81 if (!mAnimVal) { 82 mAnimVal = MakeUnique<SVGNumberList>(); 83 } 84 nsresult rv = mAnimVal->CopyFrom(aNewAnimValue); 85 if (NS_FAILED(rv)) { 86 // OOM. We clear the animation, and, importantly, ClearAnimValue() ensures 87 // that mAnimVal and its DOM wrapper (if any) will have the same length! 88 ClearAnimValue(aElement, aAttrEnum); 89 return rv; 90 } 91 aElement->DidAnimateNumberList(aAttrEnum); 92 return NS_OK; 93 } 94 95 void SVGAnimatedNumberList::ClearAnimValue(SVGElement* aElement, 96 uint32_t aAttrEnum) { 97 DOMSVGAnimatedNumberList* domWrapper = 98 DOMSVGAnimatedNumberList::GetDOMWrapperIfExists(this); 99 if (domWrapper) { 100 // When all animation ends, animVal simply mirrors baseVal, which may have 101 // a different number of items to the last active animated value. We must 102 // keep the length of our animVal's DOM wrapper list in sync, and again we 103 // must do that before touching mAnimVal. See comments above. 104 // 105 domWrapper->InternalAnimValListWillChangeTo(mBaseVal); 106 } 107 mAnimVal = nullptr; 108 aElement->DidAnimateNumberList(aAttrEnum); 109 } 110 111 UniquePtr<SMILAttr> SVGAnimatedNumberList::ToSMILAttr(SVGElement* aSVGElement, 112 uint8_t aAttrEnum) { 113 return MakeUnique<SMILAnimatedNumberList>(this, aSVGElement, aAttrEnum); 114 } 115 116 nsresult SVGAnimatedNumberList::SMILAnimatedNumberList::ValueFromString( 117 const nsAString& aStr, const dom::SVGAnimationElement* /*aSrcElement*/, 118 SMILValue& aValue, bool& aPreventCachingOfSandwich) const { 119 SMILValue val(&SVGNumberListSMILType::sSingleton); 120 SVGNumberListAndInfo* nlai = static_cast<SVGNumberListAndInfo*>(val.mU.mPtr); 121 nsresult rv = nlai->SetValueFromString(aStr); 122 if (NS_SUCCEEDED(rv)) { 123 nlai->SetInfo(mElement); 124 aValue = std::move(val); 125 } 126 return rv; 127 } 128 129 SMILValue SVGAnimatedNumberList::SMILAnimatedNumberList::GetBaseValue() const { 130 // To benefit from Return Value Optimization and avoid copy constructor calls 131 // due to our use of return-by-value, we must return the exact same object 132 // from ALL return points. This function must only return THIS variable: 133 SMILValue val; 134 135 SMILValue tmp(&SVGNumberListSMILType::sSingleton); 136 SVGNumberListAndInfo* nlai = static_cast<SVGNumberListAndInfo*>(tmp.mU.mPtr); 137 nsresult rv = nlai->CopyFrom(mVal->mBaseVal); 138 if (NS_SUCCEEDED(rv)) { 139 nlai->SetInfo(mElement); 140 std::swap(val, tmp); 141 } 142 return val; 143 } 144 145 nsresult SVGAnimatedNumberList::SMILAnimatedNumberList::SetAnimValue( 146 const SMILValue& aValue) { 147 NS_ASSERTION(aValue.mType == &SVGNumberListSMILType::sSingleton, 148 "Unexpected type to assign animated value"); 149 if (aValue.mType == &SVGNumberListSMILType::sSingleton) { 150 mVal->SetAnimValue(*static_cast<SVGNumberListAndInfo*>(aValue.mU.mPtr), 151 mElement, mAttrEnum); 152 } 153 return NS_OK; 154 } 155 156 void SVGAnimatedNumberList::SMILAnimatedNumberList::ClearAnimValue() { 157 if (mVal->mAnimVal) { 158 mVal->ClearAnimValue(mElement, mAttrEnum); 159 } 160 } 161 162 } // namespace mozilla