diff options
Diffstat (limited to '')
-rw-r--r-- | dom/svg/SVGAnimatedNumberList.cpp | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/dom/svg/SVGAnimatedNumberList.cpp b/dom/svg/SVGAnimatedNumberList.cpp new file mode 100644 index 0000000000..c9092f56ed --- /dev/null +++ b/dom/svg/SVGAnimatedNumberList.cpp @@ -0,0 +1,161 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SVGAnimatedNumberList.h" + +#include <utility> + +#include "DOMSVGAnimatedNumberList.h" +#include "SVGNumberListSMILType.h" +#include "mozilla/SMILValue.h" +#include "mozilla/dom/SVGElement.h" + +using namespace mozilla::dom; + +namespace mozilla { + +nsresult SVGAnimatedNumberList::SetBaseValueString(const nsAString& aValue) { + SVGNumberList newBaseValue; + MOZ_TRY(newBaseValue.SetValueFromString(aValue)); + + DOMSVGAnimatedNumberList* domWrapper = + DOMSVGAnimatedNumberList::GetDOMWrapperIfExists(this); + if (domWrapper) { + // We must send this notification *before* changing mBaseVal! If the length + // of our baseVal is being reduced, our baseVal's DOM wrapper list may have + // to remove DOM items from itself, and any removed DOM items need to copy + // their internal counterpart values *before* we change them. + // + domWrapper->InternalBaseValListWillChangeTo(newBaseValue); + } + + // We don't need to call DidChange* here - we're only called by + // SVGElement::ParseAttribute under Element::SetAttr, + // which takes care of notifying. + + mIsBaseSet = true; + mBaseVal.SwapWith(newBaseValue); + return NS_OK; +} + +void SVGAnimatedNumberList::ClearBaseValue(uint32_t aAttrEnum) { + DOMSVGAnimatedNumberList* domWrapper = + DOMSVGAnimatedNumberList::GetDOMWrapperIfExists(this); + if (domWrapper) { + // We must send this notification *before* changing mBaseVal! (See above.) + domWrapper->InternalBaseValListWillChangeTo(SVGNumberList()); + } + mBaseVal.Clear(); + mIsBaseSet = false; + // Caller notifies +} + +nsresult SVGAnimatedNumberList::SetAnimValue(const SVGNumberList& aNewAnimValue, + SVGElement* aElement, + uint32_t aAttrEnum) { + DOMSVGAnimatedNumberList* domWrapper = + DOMSVGAnimatedNumberList::GetDOMWrapperIfExists(this); + if (domWrapper) { + // A new animation may totally change the number of items in the animVal + // list, replacing what was essentially a mirror of the baseVal list, or + // else replacing and overriding an existing animation. When this happens + // we must try and keep our animVal's DOM wrapper in sync (see the comment + // in DOMSVGAnimatedNumberList::InternalBaseValListWillChangeTo). + // + // It's not possible for us to reliably distinguish between calls to this + // method that are setting a new sample for an existing animation, and + // calls that are setting the first sample of an animation that will + // override an existing animation. Happily it's cheap to just blindly + // notify our animVal's DOM wrapper of its internal counterpart's new value + // each time this method is called, so that's what we do. + // + // Note that we must send this notification *before* setting or changing + // mAnimVal! (See the comment in SetBaseValueString above.) + // + domWrapper->InternalAnimValListWillChangeTo(aNewAnimValue); + } + if (!mAnimVal) { + mAnimVal = MakeUnique<SVGNumberList>(); + } + nsresult rv = mAnimVal->CopyFrom(aNewAnimValue); + if (NS_FAILED(rv)) { + // OOM. We clear the animation, and, importantly, ClearAnimValue() ensures + // that mAnimVal and its DOM wrapper (if any) will have the same length! + ClearAnimValue(aElement, aAttrEnum); + return rv; + } + aElement->DidAnimateNumberList(aAttrEnum); + return NS_OK; +} + +void SVGAnimatedNumberList::ClearAnimValue(SVGElement* aElement, + uint32_t aAttrEnum) { + DOMSVGAnimatedNumberList* domWrapper = + DOMSVGAnimatedNumberList::GetDOMWrapperIfExists(this); + if (domWrapper) { + // When all animation ends, animVal simply mirrors baseVal, which may have + // a different number of items to the last active animated value. We must + // keep the length of our animVal's DOM wrapper list in sync, and again we + // must do that before touching mAnimVal. See comments above. + // + domWrapper->InternalAnimValListWillChangeTo(mBaseVal); + } + mAnimVal = nullptr; + aElement->DidAnimateNumberList(aAttrEnum); +} + +UniquePtr<SMILAttr> SVGAnimatedNumberList::ToSMILAttr(SVGElement* aSVGElement, + uint8_t aAttrEnum) { + return MakeUnique<SMILAnimatedNumberList>(this, aSVGElement, aAttrEnum); +} + +nsresult SVGAnimatedNumberList::SMILAnimatedNumberList::ValueFromString( + const nsAString& aStr, const dom::SVGAnimationElement* /*aSrcElement*/, + SMILValue& aValue, bool& aPreventCachingOfSandwich) const { + SMILValue val(&SVGNumberListSMILType::sSingleton); + SVGNumberListAndInfo* nlai = static_cast<SVGNumberListAndInfo*>(val.mU.mPtr); + nsresult rv = nlai->SetValueFromString(aStr); + if (NS_SUCCEEDED(rv)) { + nlai->SetInfo(mElement); + aValue = std::move(val); + } + return rv; +} + +SMILValue SVGAnimatedNumberList::SMILAnimatedNumberList::GetBaseValue() const { + // To benefit from Return Value Optimization and avoid copy constructor calls + // due to our use of return-by-value, we must return the exact same object + // from ALL return points. This function must only return THIS variable: + SMILValue val; + + SMILValue tmp(&SVGNumberListSMILType::sSingleton); + SVGNumberListAndInfo* nlai = static_cast<SVGNumberListAndInfo*>(tmp.mU.mPtr); + nsresult rv = nlai->CopyFrom(mVal->mBaseVal); + if (NS_SUCCEEDED(rv)) { + nlai->SetInfo(mElement); + std::swap(val, tmp); + } + return val; +} + +nsresult SVGAnimatedNumberList::SMILAnimatedNumberList::SetAnimValue( + const SMILValue& aValue) { + NS_ASSERTION(aValue.mType == &SVGNumberListSMILType::sSingleton, + "Unexpected type to assign animated value"); + if (aValue.mType == &SVGNumberListSMILType::sSingleton) { + mVal->SetAnimValue(*static_cast<SVGNumberListAndInfo*>(aValue.mU.mPtr), + mElement, mAttrEnum); + } + return NS_OK; +} + +void SVGAnimatedNumberList::SMILAnimatedNumberList::ClearAnimValue() { + if (mVal->mAnimVal) { + mVal->ClearAnimValue(mElement, mAttrEnum); + } +} + +} // namespace mozilla |