Bug 1700051: part 46) Const-qualify `mozInlineSpellStatus::mAnchorRange`. r=smaug
[gecko.git] / dom / svg / DOMSVGLength.cpp
blobb3b06d711b07ab0decc221e5079ca99ab6eeb9bb
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 "DOMSVGLength.h"
9 #include "DOMSVGLengthList.h"
10 #include "DOMSVGAnimatedLengthList.h"
11 #include "nsError.h"
12 #include "nsMathUtils.h"
13 #include "SVGAnimatedLength.h"
14 #include "SVGAnimatedLengthList.h"
15 #include "SVGAttrTearoffTable.h"
16 #include "SVGLength.h"
17 #include "mozilla/dom/SVGElement.h"
18 #include "mozilla/dom/SVGLengthBinding.h"
19 #include "mozilla/FloatingPoint.h"
21 // See the architecture comment in DOMSVGAnimatedLengthList.h.
23 namespace mozilla {
25 namespace dom {
27 static SVGAttrTearoffTable<SVGAnimatedLength, DOMSVGLength>
28 sBaseSVGLengthTearOffTable, sAnimSVGLengthTearOffTable;
30 // We could use NS_IMPL_CYCLE_COLLECTION(, except that in Unlink() we need to
31 // clear our list's weak ref to us to be safe. (The other option would be to
32 // not unlink and rely on the breaking of the other edges in the cycle, as
33 // NS_SVG_VAL_IMPL_CYCLE_COLLECTION does.)
34 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGLength)
36 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGLength)
37 tmp->CleanupWeakRefs();
38 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner)
39 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
40 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
42 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGLength)
43 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner)
44 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
46 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGLength)
47 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
48 NS_IMPL_CYCLE_COLLECTION_TRACE_END
50 NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMSVGLength, AddRef)
51 NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMSVGLength, Release)
53 DOMSVGLength::DOMSVGLength(DOMSVGLengthList* aList, uint8_t aAttrEnum,
54 uint32_t aListIndex, bool aIsAnimValItem)
55 : mOwner(aList),
56 mListIndex(aListIndex),
57 mAttrEnum(aAttrEnum),
58 mIsAnimValItem(aIsAnimValItem),
59 mUnit(SVGLength_Binding::SVG_LENGTHTYPE_NUMBER) {
60 MOZ_ASSERT(aList, "bad arg");
61 MOZ_ASSERT(mAttrEnum == aAttrEnum, "bitfield too small");
62 MOZ_ASSERT(aListIndex <= MaxListIndex(), "list index too large");
63 MOZ_ASSERT(IndexIsValid(), "Bad index for DOMSVGNumber!");
66 DOMSVGLength::DOMSVGLength()
67 : mOwner(nullptr),
68 mListIndex(0),
69 mAttrEnum(0),
70 mIsAnimValItem(false),
71 mUnit(SVGLength_Binding::SVG_LENGTHTYPE_NUMBER) {}
73 DOMSVGLength::DOMSVGLength(SVGAnimatedLength* aVal, SVGElement* aSVGElement,
74 bool aAnimVal)
75 : mOwner(aSVGElement),
76 mListIndex(0),
77 mAttrEnum(aVal->mAttrEnum),
78 mIsAnimValItem(aAnimVal),
79 mUnit(SVGLength_Binding::SVG_LENGTHTYPE_NUMBER) {
80 MOZ_ASSERT(aVal, "bad arg");
81 MOZ_ASSERT(mAttrEnum == aVal->mAttrEnum, "bitfield too small");
84 void DOMSVGLength::CleanupWeakRefs() {
85 // Our mList's weak ref to us must be nulled out when we die (or when we're
86 // cycle collected), so we that don't leave behind a pointer to
87 // free / soon-to-be-free memory.
88 if (nsCOMPtr<DOMSVGLengthList> lengthList = do_QueryInterface(mOwner)) {
89 MOZ_ASSERT(lengthList->mItems[mListIndex] == this,
90 "Clearing out the wrong list index...?");
91 lengthList->mItems[mListIndex] = nullptr;
94 // Similarly, we must update the tearoff table to remove its (non-owning)
95 // pointer to mVal.
96 if (nsCOMPtr<SVGElement> svg = do_QueryInterface(mOwner)) {
97 auto& table = mIsAnimValItem ? sAnimSVGLengthTearOffTable
98 : sBaseSVGLengthTearOffTable;
99 table.RemoveTearoff(svg->GetAnimatedLength(mAttrEnum));
103 already_AddRefed<DOMSVGLength> DOMSVGLength::GetTearOff(SVGAnimatedLength* aVal,
104 SVGElement* aSVGElement,
105 bool aAnimVal) {
106 auto& table =
107 aAnimVal ? sAnimSVGLengthTearOffTable : sBaseSVGLengthTearOffTable;
108 RefPtr<DOMSVGLength> domLength = table.GetTearoff(aVal);
109 if (!domLength) {
110 domLength = new DOMSVGLength(aVal, aSVGElement, aAnimVal);
111 table.AddTearoff(aVal, domLength);
114 return domLength.forget();
117 DOMSVGLength* DOMSVGLength::Copy() {
118 NS_ASSERTION(HasOwner(), "unexpected caller");
119 DOMSVGLength* copy = new DOMSVGLength();
120 uint16_t unit;
121 float value;
122 if (nsCOMPtr<SVGElement> svg = do_QueryInterface(mOwner)) {
123 SVGAnimatedLength* length = svg->GetAnimatedLength(mAttrEnum);
124 unit = length->GetSpecifiedUnitType();
125 value = mIsAnimValItem ? length->GetAnimValInSpecifiedUnits()
126 : length->GetBaseValInSpecifiedUnits();
127 } else {
128 const SVGLength& length = InternalItem();
129 unit = length.GetUnit();
130 value = length.GetValueInCurrentUnits();
132 copy->NewValueSpecifiedUnits(unit, value, IgnoreErrors());
133 return copy;
136 uint16_t DOMSVGLength::UnitType() {
137 if (mIsAnimValItem) {
138 Element()->FlushAnimations();
140 if (nsCOMPtr<SVGElement> svg = do_QueryInterface(mOwner)) {
141 return svg->GetAnimatedLength(mAttrEnum)->GetSpecifiedUnitType();
143 return HasOwner() ? InternalItem().GetUnit() : mUnit;
146 float DOMSVGLength::GetValue(ErrorResult& aRv) {
147 if (mIsAnimValItem) {
148 Element()->FlushAnimations(); // May make HasOwner() == false
151 if (nsCOMPtr<SVGElement> svg = do_QueryInterface(mOwner)) {
152 SVGAnimatedLength* length = svg->GetAnimatedLength(mAttrEnum);
153 return mIsAnimValItem ? length->GetAnimValue(svg)
154 : length->GetBaseValue(svg);
157 if (nsCOMPtr<DOMSVGLengthList> lengthList = do_QueryInterface(mOwner)) {
158 float value = InternalItem().GetValueInUserUnits(lengthList->Element(),
159 lengthList->Axis());
160 if (!IsFinite(value)) {
161 aRv.Throw(NS_ERROR_FAILURE);
163 return value;
166 float unitToPx;
167 if (UserSpaceMetrics::ResolveAbsoluteUnit(mUnit, unitToPx)) {
168 return mValue * unitToPx;
171 // else [SVGWG issue] Can't convert this length's value to user units
172 // ReportToConsole
173 aRv.Throw(NS_ERROR_FAILURE);
174 return 0.0f;
177 void DOMSVGLength::SetValue(float aUserUnitValue, ErrorResult& aRv) {
178 if (mIsAnimValItem) {
179 aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
180 return;
183 if (nsCOMPtr<SVGElement> svg = do_QueryInterface(mOwner)) {
184 aRv = svg->GetAnimatedLength(mAttrEnum)->SetBaseValue(aUserUnitValue, svg,
185 true);
186 return;
189 // Although the value passed in is in user units, this method does not turn
190 // this length into a user unit length. Instead it converts the user unit
191 // value to this length's current unit and sets that, leaving this length's
192 // unit as it is.
194 if (nsCOMPtr<DOMSVGLengthList> lengthList = do_QueryInterface(mOwner)) {
195 SVGLength& internalItem = InternalItem();
196 if (internalItem.GetValueInUserUnits(
197 lengthList->Element(), lengthList->Axis()) == aUserUnitValue) {
198 return;
200 float uuPerUnit = internalItem.GetUserUnitsPerUnit(lengthList->Element(),
201 lengthList->Axis());
202 if (uuPerUnit > 0) {
203 float newValue = aUserUnitValue / uuPerUnit;
204 if (IsFinite(newValue)) {
205 AutoChangeLengthListNotifier notifier(this);
206 internalItem.SetValueAndUnit(newValue, internalItem.GetUnit());
207 return;
210 } else if (mUnit == SVGLength_Binding::SVG_LENGTHTYPE_NUMBER ||
211 mUnit == SVGLength_Binding::SVG_LENGTHTYPE_PX) {
212 mValue = aUserUnitValue;
213 return;
215 // else [SVGWG issue] Can't convert user unit value to this length's unit
216 // ReportToConsole
217 aRv.Throw(NS_ERROR_FAILURE);
220 float DOMSVGLength::ValueInSpecifiedUnits() {
221 if (mIsAnimValItem) {
222 Element()->FlushAnimations(); // May make HasOwner() == false
224 if (nsCOMPtr<SVGElement> svg = do_QueryInterface(mOwner)) {
225 SVGAnimatedLength* length = svg->GetAnimatedLength(mAttrEnum);
226 return mIsAnimValItem ? length->GetAnimValInSpecifiedUnits()
227 : length->GetBaseValInSpecifiedUnits();
230 return HasOwner() ? InternalItem().GetValueInCurrentUnits() : mValue;
233 void DOMSVGLength::SetValueInSpecifiedUnits(float aValue, ErrorResult& aRv) {
234 if (mIsAnimValItem) {
235 aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
236 return;
239 if (nsCOMPtr<SVGElement> svg = do_QueryInterface(mOwner)) {
240 svg->GetAnimatedLength(mAttrEnum)->SetBaseValueInSpecifiedUnits(aValue, svg,
241 true);
242 return;
245 if (HasOwner()) {
246 SVGLength& internalItem = InternalItem();
247 if (internalItem.GetValueInCurrentUnits() == aValue) {
248 return;
250 AutoChangeLengthListNotifier notifier(this);
251 internalItem.SetValueInCurrentUnits(aValue);
252 return;
254 mValue = aValue;
257 void DOMSVGLength::SetValueAsString(const nsAString& aValue, ErrorResult& aRv) {
258 if (mIsAnimValItem) {
259 aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
260 return;
263 if (nsCOMPtr<SVGElement> svg = do_QueryInterface(mOwner)) {
264 aRv = svg->GetAnimatedLength(mAttrEnum)->SetBaseValueString(aValue, svg,
265 true);
266 return;
269 SVGLength value;
270 if (!value.SetValueFromString(aValue)) {
271 aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
272 return;
274 if (HasOwner()) {
275 SVGLength& internalItem = InternalItem();
276 if (internalItem == value) {
277 return;
279 AutoChangeLengthListNotifier notifier(this);
280 internalItem = value;
281 return;
283 mValue = value.GetValueInCurrentUnits();
284 mUnit = value.GetUnit();
287 void DOMSVGLength::GetValueAsString(nsAString& aValue) {
288 if (mIsAnimValItem) {
289 Element()->FlushAnimations(); // May make HasOwner() == false
292 if (nsCOMPtr<SVGElement> svg = do_QueryInterface(mOwner)) {
293 SVGAnimatedLength* length = svg->GetAnimatedLength(mAttrEnum);
294 if (mIsAnimValItem) {
295 length->GetAnimValueString(aValue);
296 } else {
297 length->GetBaseValueString(aValue);
299 return;
301 if (HasOwner()) {
302 InternalItem().GetValueAsString(aValue);
303 return;
305 SVGLength(mValue, mUnit).GetValueAsString(aValue);
308 void DOMSVGLength::NewValueSpecifiedUnits(uint16_t aUnit, float aValue,
309 ErrorResult& aRv) {
310 if (mIsAnimValItem) {
311 aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
312 return;
315 if (nsCOMPtr<SVGElement> svg = do_QueryInterface(mOwner)) {
316 svg->GetAnimatedLength(mAttrEnum)->NewValueSpecifiedUnits(aUnit, aValue,
317 svg);
318 return;
321 if (!SVGLength::IsValidUnitType(aUnit)) {
322 aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
323 return;
325 if (HasOwner()) {
326 SVGLength& internalItem = InternalItem();
327 if (internalItem == SVGLength(aValue, aUnit)) {
328 return;
330 AutoChangeLengthListNotifier notifier(this);
331 internalItem.SetValueAndUnit(aValue, uint8_t(aUnit));
332 return;
334 mUnit = uint8_t(aUnit);
335 mValue = aValue;
338 void DOMSVGLength::ConvertToSpecifiedUnits(uint16_t aUnit, ErrorResult& aRv) {
339 if (mIsAnimValItem) {
340 aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
341 return;
344 if (nsCOMPtr<SVGElement> svg = do_QueryInterface(mOwner)) {
345 svg->GetAnimatedLength(mAttrEnum)->ConvertToSpecifiedUnits(aUnit, svg);
346 return;
349 if (!SVGLength::IsValidUnitType(aUnit)) {
350 aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
351 return;
354 float val;
355 if (nsCOMPtr<DOMSVGLengthList> lengthList = do_QueryInterface(mOwner)) {
356 SVGLength& length = InternalItem();
357 if (length.GetUnit() == aUnit) {
358 return;
360 val = length.GetValueInSpecifiedUnit(aUnit, lengthList->Element(),
361 lengthList->Axis());
362 } else {
363 val = SVGLength(mValue, mUnit).GetValueInSpecifiedUnit(aUnit, nullptr, 0);
365 if (IsFinite(val)) {
366 if (HasOwner()) {
367 AutoChangeLengthListNotifier notifier(this);
368 InternalItem().SetValueAndUnit(val, aUnit);
369 } else {
370 mValue = val;
371 mUnit = aUnit;
373 return;
375 // else [SVGWG issue] Can't convert unit
376 // ReportToConsole
377 aRv.Throw(NS_ERROR_FAILURE);
380 JSObject* DOMSVGLength::WrapObject(JSContext* aCx,
381 JS::Handle<JSObject*> aGivenProto) {
382 return SVGLength_Binding::Wrap(aCx, this, aGivenProto);
385 void DOMSVGLength::InsertingIntoList(DOMSVGLengthList* aList, uint8_t aAttrEnum,
386 uint32_t aListIndex, bool aIsAnimValItem) {
387 NS_ASSERTION(!HasOwner(), "Inserting item that is already in a list");
389 mOwner = aList;
390 mAttrEnum = aAttrEnum;
391 mListIndex = aListIndex;
392 mIsAnimValItem = aIsAnimValItem;
394 MOZ_ASSERT(IndexIsValid(), "Bad index for DOMSVGLength!");
397 void DOMSVGLength::RemovingFromList() {
398 mValue = InternalItem().GetValueInCurrentUnits();
399 mUnit = InternalItem().GetUnit();
400 mOwner = nullptr;
401 mIsAnimValItem = false;
404 SVGLength DOMSVGLength::ToSVGLength() {
405 if (nsCOMPtr<SVGElement> svg = do_QueryInterface(mOwner)) {
406 SVGAnimatedLength* length = svg->GetAnimatedLength(mAttrEnum);
407 return SVGLength(mIsAnimValItem ? length->GetAnimValInSpecifiedUnits()
408 : length->GetBaseValInSpecifiedUnits(),
409 length->GetSpecifiedUnitType());
411 return HasOwner() ? InternalItem() : SVGLength(mValue, mUnit);
414 bool DOMSVGLength::IsAnimating() const {
415 if (nsCOMPtr<DOMSVGLengthList> lengthList = do_QueryInterface(mOwner)) {
416 return lengthList->IsAnimating();
418 nsCOMPtr<SVGElement> svg = do_QueryInterface(mOwner);
419 return svg && svg->GetAnimatedLength(mAttrEnum)->IsAnimated();
422 SVGElement* DOMSVGLength::Element() {
423 if (nsCOMPtr<DOMSVGLengthList> lengthList = do_QueryInterface(mOwner)) {
424 return lengthList->Element();
426 nsCOMPtr<SVGElement> svg = do_QueryInterface(mOwner);
427 return svg;
430 SVGLength& DOMSVGLength::InternalItem() {
431 nsCOMPtr<DOMSVGLengthList> lengthList = do_QueryInterface(mOwner);
432 SVGAnimatedLengthList* alist =
433 lengthList->Element()->GetAnimatedLengthList(mAttrEnum);
434 return mIsAnimValItem && alist->mAnimVal ? (*alist->mAnimVal)[mListIndex]
435 : alist->mBaseVal[mListIndex];
438 #ifdef DEBUG
439 bool DOMSVGLength::IndexIsValid() {
440 nsCOMPtr<DOMSVGLengthList> lengthList = do_QueryInterface(mOwner);
441 SVGAnimatedLengthList* alist =
442 lengthList->Element()->GetAnimatedLengthList(mAttrEnum);
443 return (mIsAnimValItem && mListIndex < alist->GetAnimValue().Length()) ||
444 (!mIsAnimValItem && mListIndex < alist->GetBaseValue().Length());
446 #endif
448 } // namespace dom
449 } // namespace mozilla