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