Bug 1700051: part 46) Const-qualify `mozInlineSpellStatus::mAnchorRange`. r=smaug
[gecko.git] / dom / svg / SVGAnimatedPointList.cpp
blob471b925c7ed0ecc4a762fb3300624d122601869a
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/. */
7 #include "SVGAnimatedPointList.h"
9 #include <utility>
11 #include "DOMSVGPointList.h"
12 #include "SVGPointListSMILType.h"
13 #include "mozilla/SMILValue.h"
14 #include "mozilla/dom/SVGElement.h"
16 using namespace mozilla::dom;
18 // See the comments in this file's header!
20 namespace mozilla {
22 nsresult SVGAnimatedPointList::SetBaseValueString(const nsAString& aValue) {
23 SVGPointList newBaseValue;
25 // The spec says that the point data is parsed and accepted up to the first
26 // error encountered, so we don't return early if an error occurs. However,
27 // we do want to throw any error code from setAttribute if there's a problem.
29 nsresult rv = newBaseValue.SetValueFromString(aValue);
31 // We must send these notifications *before* changing mBaseVal! Our baseVal's
32 // DOM wrapper list may have to remove DOM items from itself, and any removed
33 // DOM items need to copy their internal counterpart's values *before* we
34 // change them. See the comments in
35 // DOMSVGPointList::InternalListWillChangeTo().
37 DOMSVGPointList* baseValWrapper =
38 DOMSVGPointList::GetDOMWrapperIfExists(GetBaseValKey());
39 if (baseValWrapper) {
40 baseValWrapper->InternalListWillChangeTo(newBaseValue);
43 DOMSVGPointList* animValWrapper = nullptr;
44 if (!IsAnimating()) { // DOM anim val wraps our base val too!
45 animValWrapper = DOMSVGPointList::GetDOMWrapperIfExists(GetAnimValKey());
46 if (animValWrapper) {
47 animValWrapper->InternalListWillChangeTo(newBaseValue);
51 // Only now may we modify mBaseVal!
53 // We don't need to call DidChange* here - we're only called by
54 // SVGElement::ParseAttribute under Element::SetAttr,
55 // which takes care of notifying.
57 nsresult rv2 = mBaseVal.CopyFrom(newBaseValue);
58 if (NS_FAILED(rv2)) {
59 // Attempting to increase mBaseVal's length failed (mBaseVal is left
60 // unmodified). We MUST keep any DOM wrappers in sync:
61 if (baseValWrapper) {
62 baseValWrapper->InternalListWillChangeTo(mBaseVal);
64 if (animValWrapper) {
65 animValWrapper->InternalListWillChangeTo(mBaseVal);
67 return rv2;
69 return rv;
72 void SVGAnimatedPointList::ClearBaseValue() {
73 // We must send these notifications *before* changing mBaseVal! (See above.)
75 DOMSVGPointList* baseValWrapper =
76 DOMSVGPointList::GetDOMWrapperIfExists(GetBaseValKey());
77 if (baseValWrapper) {
78 baseValWrapper->InternalListWillChangeTo(SVGPointList());
81 if (!IsAnimating()) { // DOM anim val wraps our base val too!
82 DOMSVGPointList* animValWrapper =
83 DOMSVGPointList::GetDOMWrapperIfExists(GetAnimValKey());
84 if (animValWrapper) {
85 animValWrapper->InternalListWillChangeTo(SVGPointList());
89 mBaseVal.Clear();
90 // Caller notifies
93 nsresult SVGAnimatedPointList::SetAnimValue(const SVGPointList& aNewAnimValue,
94 SVGElement* aElement) {
95 // Note that a new animation may totally change the number of items in the
96 // animVal list, either replacing what was essentially a mirror of the
97 // baseVal list, or else replacing and overriding an existing animation.
98 // It is not possible for us to reliably distinguish between calls to this
99 // method that are setting a new sample for an existing animation (in which
100 // case our list length isn't changing and we wouldn't need to notify our DOM
101 // wrapper to keep its length in sync), and calls to this method that are
102 // setting the first sample of a new animation that will override the base
103 // value/an existing animation (in which case our length may be changing and
104 // our DOM wrapper may need to be notified). Happily though, it's cheap to
105 // just blindly notify our animVal's DOM wrapper of our new value each time
106 // this method is called, so that's what we do.
108 // We must send this notification *before* changing mAnimVal! (See above.)
110 DOMSVGPointList* domWrapper =
111 DOMSVGPointList::GetDOMWrapperIfExists(GetAnimValKey());
112 if (domWrapper) {
113 domWrapper->InternalListWillChangeTo(aNewAnimValue);
115 if (!mAnimVal) {
116 mAnimVal = MakeUnique<SVGPointList>();
118 nsresult rv = mAnimVal->CopyFrom(aNewAnimValue);
119 if (NS_FAILED(rv)) {
120 // OOM. We clear the animation and, importantly, ClearAnimValue() ensures
121 // that mAnimVal's DOM wrapper (if any) is kept in sync!
122 ClearAnimValue(aElement);
123 return rv;
125 aElement->DidAnimatePointList();
126 return NS_OK;
129 void SVGAnimatedPointList::ClearAnimValue(SVGElement* aElement) {
130 // We must send these notifications *before* changing mAnimVal! (See above.)
132 DOMSVGPointList* domWrapper =
133 DOMSVGPointList::GetDOMWrapperIfExists(GetAnimValKey());
134 if (domWrapper) {
135 // When all animation ends, animVal simply mirrors baseVal, which may have
136 // a different number of items to the last active animated value.
138 domWrapper->InternalListWillChangeTo(mBaseVal);
140 mAnimVal = nullptr;
141 aElement->DidAnimatePointList();
144 UniquePtr<SMILAttr> SVGAnimatedPointList::ToSMILAttr(SVGElement* aElement) {
145 return MakeUnique<SMILAnimatedPointList>(this, aElement);
148 nsresult SVGAnimatedPointList::SMILAnimatedPointList::ValueFromString(
149 const nsAString& aStr, const dom::SVGAnimationElement* /*aSrcElement*/,
150 SMILValue& aValue, bool& aPreventCachingOfSandwich) const {
151 SMILValue val(&SVGPointListSMILType::sSingleton);
152 SVGPointListAndInfo* list = static_cast<SVGPointListAndInfo*>(val.mU.mPtr);
153 nsresult rv = list->SetValueFromString(aStr);
154 if (NS_SUCCEEDED(rv)) {
155 list->SetInfo(mElement);
156 aValue = std::move(val);
158 aPreventCachingOfSandwich = false;
159 return rv;
162 SMILValue SVGAnimatedPointList::SMILAnimatedPointList::GetBaseValue() const {
163 // To benefit from Return Value Optimization and avoid copy constructor calls
164 // due to our use of return-by-value, we must return the exact same object
165 // from ALL return points. This function must only return THIS variable:
166 SMILValue val;
168 SMILValue tmp(&SVGPointListSMILType::sSingleton);
169 SVGPointListAndInfo* list = static_cast<SVGPointListAndInfo*>(tmp.mU.mPtr);
170 nsresult rv = list->CopyFrom(mVal->mBaseVal);
171 if (NS_SUCCEEDED(rv)) {
172 list->SetInfo(mElement);
173 std::swap(val, tmp);
175 return val;
178 nsresult SVGAnimatedPointList::SMILAnimatedPointList::SetAnimValue(
179 const SMILValue& aValue) {
180 NS_ASSERTION(aValue.mType == &SVGPointListSMILType::sSingleton,
181 "Unexpected type to assign animated value");
182 if (aValue.mType == &SVGPointListSMILType::sSingleton) {
183 mVal->SetAnimValue(*static_cast<SVGPointListAndInfo*>(aValue.mU.mPtr),
184 mElement);
186 return NS_OK;
189 void SVGAnimatedPointList::SMILAnimatedPointList::ClearAnimValue() {
190 if (mVal->mAnimVal) {
191 mVal->ClearAnimValue(mElement);
195 } // namespace mozilla