Bug 1936278 - Prevent search mode chiclet from being dismissed when clicking in page...
[gecko.git] / dom / svg / SVGAnimatedPointList.cpp
blob797f4ec4ce559e917a35c6bb6e983d3ce3fcba1e
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 mBaseVal.SwapWith(newBaseValue);
58 return rv;
61 void SVGAnimatedPointList::ClearBaseValue() {
62 // We must send these notifications *before* changing mBaseVal! (See above.)
64 DOMSVGPointList* baseValWrapper =
65 DOMSVGPointList::GetDOMWrapperIfExists(GetBaseValKey());
66 if (baseValWrapper) {
67 baseValWrapper->InternalListWillChangeTo(SVGPointList());
70 if (!IsAnimating()) { // DOM anim val wraps our base val too!
71 DOMSVGPointList* animValWrapper =
72 DOMSVGPointList::GetDOMWrapperIfExists(GetAnimValKey());
73 if (animValWrapper) {
74 animValWrapper->InternalListWillChangeTo(SVGPointList());
78 mBaseVal.Clear();
79 // Caller notifies
82 nsresult SVGAnimatedPointList::SetAnimValue(const SVGPointList& aNewAnimValue,
83 SVGElement* aElement) {
84 // Note that a new animation may totally change the number of items in the
85 // animVal list, either replacing what was essentially a mirror of the
86 // baseVal list, or else replacing and overriding an existing animation.
87 // It is not possible for us to reliably distinguish between calls to this
88 // method that are setting a new sample for an existing animation (in which
89 // case our list length isn't changing and we wouldn't need to notify our DOM
90 // wrapper to keep its length in sync), and calls to this method that are
91 // setting the first sample of a new animation that will override the base
92 // value/an existing animation (in which case our length may be changing and
93 // our DOM wrapper may need to be notified). Happily though, it's cheap to
94 // just blindly notify our animVal's DOM wrapper of our new value each time
95 // this method is called, so that's what we do.
97 // We must send this notification *before* changing mAnimVal! (See above.)
99 DOMSVGPointList* domWrapper =
100 DOMSVGPointList::GetDOMWrapperIfExists(GetAnimValKey());
101 if (domWrapper) {
102 domWrapper->InternalListWillChangeTo(aNewAnimValue);
104 if (!mAnimVal) {
105 mAnimVal = MakeUnique<SVGPointList>();
107 nsresult rv = mAnimVal->CopyFrom(aNewAnimValue);
108 if (NS_FAILED(rv)) {
109 // OOM. We clear the animation and, importantly, ClearAnimValue() ensures
110 // that mAnimVal's DOM wrapper (if any) is kept in sync!
111 ClearAnimValue(aElement);
112 return rv;
114 aElement->DidAnimatePointList();
115 return NS_OK;
118 void SVGAnimatedPointList::ClearAnimValue(SVGElement* aElement) {
119 // We must send these notifications *before* changing mAnimVal! (See above.)
121 DOMSVGPointList* domWrapper =
122 DOMSVGPointList::GetDOMWrapperIfExists(GetAnimValKey());
123 if (domWrapper) {
124 // When all animation ends, animVal simply mirrors baseVal, which may have
125 // a different number of items to the last active animated value.
127 domWrapper->InternalListWillChangeTo(mBaseVal);
129 mAnimVal = nullptr;
130 aElement->DidAnimatePointList();
133 UniquePtr<SMILAttr> SVGAnimatedPointList::ToSMILAttr(SVGElement* aElement) {
134 return MakeUnique<SMILAnimatedPointList>(this, aElement);
137 nsresult SVGAnimatedPointList::SMILAnimatedPointList::ValueFromString(
138 const nsAString& aStr, const dom::SVGAnimationElement* /*aSrcElement*/,
139 SMILValue& aValue, bool& aPreventCachingOfSandwich) const {
140 SMILValue val(&SVGPointListSMILType::sSingleton);
141 SVGPointListAndInfo* list = static_cast<SVGPointListAndInfo*>(val.mU.mPtr);
142 nsresult rv = list->SetValueFromString(aStr);
143 if (NS_SUCCEEDED(rv)) {
144 list->SetInfo(mElement);
145 aValue = std::move(val);
147 return rv;
150 SMILValue SVGAnimatedPointList::SMILAnimatedPointList::GetBaseValue() const {
151 // To benefit from Return Value Optimization and avoid copy constructor calls
152 // due to our use of return-by-value, we must return the exact same object
153 // from ALL return points. This function must only return THIS variable:
154 SMILValue val;
156 SMILValue tmp(&SVGPointListSMILType::sSingleton);
157 auto* list = static_cast<SVGPointListAndInfo*>(tmp.mU.mPtr);
158 nsresult rv = list->CopyFrom(mVal->mBaseVal);
159 if (NS_SUCCEEDED(rv)) {
160 list->SetInfo(mElement);
161 std::swap(val, tmp);
163 return val;
166 nsresult SVGAnimatedPointList::SMILAnimatedPointList::SetAnimValue(
167 const SMILValue& aValue) {
168 NS_ASSERTION(aValue.mType == &SVGPointListSMILType::sSingleton,
169 "Unexpected type to assign animated value");
170 if (aValue.mType == &SVGPointListSMILType::sSingleton) {
171 mVal->SetAnimValue(*static_cast<SVGPointListAndInfo*>(aValue.mU.mPtr),
172 mElement);
174 return NS_OK;
177 void SVGAnimatedPointList::SMILAnimatedPointList::ClearAnimValue() {
178 if (mVal->mAnimVal) {
179 mVal->ClearAnimValue(mElement);
183 } // namespace mozilla