diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /dom/svg/SVGAnimatedNumberList.cpp | |
parent | Initial commit. (diff) | |
download | firefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/svg/SVGAnimatedNumberList.cpp')
-rw-r--r-- | dom/svg/SVGAnimatedNumberList.cpp | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/dom/svg/SVGAnimatedNumberList.cpp b/dom/svg/SVGAnimatedNumberList.cpp new file mode 100644 index 0000000000..837d260bb6 --- /dev/null +++ b/dom/svg/SVGAnimatedNumberList.cpp @@ -0,0 +1,170 @@ +/* -*- 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; + nsresult rv = newBaseValue.SetValueFromString(aValue); + if (NS_FAILED(rv)) { + return rv; + } + + 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; + rv = mBaseVal.CopyFrom(newBaseValue); + if (NS_FAILED(rv) && domWrapper) { + // Attempting to increase mBaseVal's length failed - reduce domWrapper + // back to the same length: + domWrapper->InternalBaseValListWillChangeTo(mBaseVal); + } + return rv; +} + +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); + } + aPreventCachingOfSandwich = false; + 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 |