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 "DOMSVGPoint.h"
9 #include "DOMSVGPointList.h"
10 #include "gfx2DGlue.h"
12 #include "mozilla/dom/DOMMatrix.h"
13 #include "mozilla/dom/SVGPointBinding.h"
15 // See the architecture comment in DOMSVGPointList.h.
17 using namespace mozilla::gfx
;
19 namespace mozilla::dom
{
21 //----------------------------------------------------------------------
22 // Helper class: AutoChangePointNotifier
24 class MOZ_RAII AutoChangePointNotifier
{
26 explicit AutoChangePointNotifier(DOMSVGPoint
* aValue
) : mValue(aValue
) {
27 MOZ_ASSERT(mValue
, "Expecting non-null value");
30 ~AutoChangePointNotifier() {
31 if (mValue
->IsTranslatePoint()) {
32 mValue
->DidChangeTranslate();
37 DOMSVGPoint
* const mValue
;
40 MOZ_CONSTINIT
static SVGAttrTearoffTable
<SVGPoint
, DOMSVGPoint
>
41 sSVGTranslateTearOffTable
;
43 // We could use NS_IMPL_CYCLE_COLLECTION(, except that in Unlink() we need to
44 // clear our list's weak ref to us to be safe. (The other option would be to
45 // not unlink and rely on the breaking of the other edges in the cycle, as
46 // NS_SVG_VAL_IMPL_CYCLE_COLLECTION does.)
47 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGPoint
)
49 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGPoint
)
50 tmp
->CleanupWeakRefs();
51 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner
)
52 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
53 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
55 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGPoint
)
56 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner
)
57 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
59 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGPoint
)
60 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
61 NS_IMPL_CYCLE_COLLECTION_TRACE_END
63 JSObject
* DOMSVGPoint::WrapObject(JSContext
* aCx
,
64 JS::Handle
<JSObject
*> aGivenProto
) {
65 return SVGPoint_Binding::Wrap(aCx
, this, aGivenProto
);
68 float DOMSVGPoint::X() {
69 if (mIsAnimValItem
&& IsInList()) {
70 Element()->FlushAnimations(); // May make IsInList() == false
72 return InternalItem().mX
;
75 void DOMSVGPoint::SetX(float aX
, ErrorResult
& rv
) {
77 rv
.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR
);
81 auto& val
= InternalItem();
87 AutoChangePointListNotifier
listNotifier(this);
88 AutoChangePointNotifier
translateNotifier(this);
93 float DOMSVGPoint::Y() {
94 if (mIsAnimValItem
&& IsInList()) {
95 Element()->FlushAnimations(); // May make IsInList() == false
97 return InternalItem().mY
;
100 void DOMSVGPoint::SetY(float aY
, ErrorResult
& rv
) {
101 if (mIsAnimValItem
) {
102 rv
.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR
);
105 auto& val
= InternalItem();
111 AutoChangePointListNotifier
listNotifier(this);
112 AutoChangePointNotifier
translateNotifier(this);
117 already_AddRefed
<DOMSVGPoint
> DOMSVGPoint::MatrixTransform(
118 const DOMMatrix2DInit
& aMatrix
, ErrorResult
& aRv
) {
119 RefPtr
<DOMMatrixReadOnly
> matrix
=
120 DOMMatrixReadOnly::FromMatrix(GetParentObject(), aMatrix
, aRv
);
124 const auto* matrix2D
= matrix
->GetInternal2D();
125 if (!matrix2D
->IsFinite()) {
126 aRv
.ThrowTypeError
<MSG_NOT_FINITE
>("MatrixTransform matrix");
129 auto pt
= matrix2D
->TransformPoint(InternalItem());
130 return do_AddRef(new DOMSVGPoint(ToPoint(pt
)));
133 void DOMSVGPoint::InsertingIntoList(DOMSVGPointList
* aList
, uint32_t aListIndex
,
134 bool aIsAnimValItem
) {
135 MOZ_RELEASE_ASSERT(!IsInList(), "Inserting item that is already in a list");
136 MOZ_RELEASE_ASSERT(!mIsTranslatePoint
,
137 "Inserting item that is a currentTranslate");
143 mListIndex
= aListIndex
;
144 mIsAnimValItem
= aIsAnimValItem
;
146 MOZ_ASSERT(IndexIsValid(), "Bad index for DOMSVGPoint!");
149 void DOMSVGPoint::RemovingFromList() {
152 "We should start in a list if we're going to be removed from one.");
153 mVal
= new SVGPoint(InternalItem());
155 mIsAnimValItem
= false;
158 SVGPoint
& DOMSVGPoint::InternalItem() {
159 if (nsCOMPtr
<DOMSVGPointList
> pointList
= do_QueryInterface(mOwner
)) {
160 return pointList
->InternalList().mItems
[mListIndex
];
165 already_AddRefed
<DOMSVGPoint
> DOMSVGPoint::GetTranslateTearOff(
166 SVGPoint
* aVal
, SVGSVGElement
* aSVGSVGElement
) {
167 RefPtr
<DOMSVGPoint
> domPoint
= sSVGTranslateTearOffTable
.GetTearoff(aVal
);
169 domPoint
= new DOMSVGPoint(aVal
, aSVGSVGElement
);
170 sSVGTranslateTearOffTable
.AddTearoff(aVal
, domPoint
);
173 return domPoint
.forget();
176 bool DOMSVGPoint::AttrIsAnimating() const {
177 nsCOMPtr
<DOMSVGPointList
> pointList
= do_QueryInterface(mOwner
);
178 return pointList
&& pointList
->AttrIsAnimating();
181 void DOMSVGPoint::DidChangeTranslate() {
182 nsCOMPtr
<SVGSVGElement
> svg
= do_QueryInterface(mOwner
);
184 nsContentUtils::AddScriptRunner(
185 NewRunnableMethod("dom::SVGSVGElement::DidChangeTranslate", svg
,
186 &SVGSVGElement::DidChangeTranslate
));
189 SVGElement
* DOMSVGPoint::Element() {
190 if (nsCOMPtr
<DOMSVGPointList
> pointList
= do_QueryInterface(mOwner
)) {
191 return pointList
->Element();
193 nsCOMPtr
<SVGSVGElement
> svg
= do_QueryInterface(mOwner
);
197 void DOMSVGPoint::CleanupWeakRefs() {
198 // Our mList's weak ref to us must be nulled out when we die (or when we're
199 // cycle collected), so we that don't leave behind a pointer to
200 // free / soon-to-be-free memory.
201 if (nsCOMPtr
<DOMSVGPointList
> pointList
= do_QueryInterface(mOwner
)) {
202 MOZ_ASSERT(pointList
->mItems
[mListIndex
] == this,
203 "Clearing out the wrong list index...?");
204 pointList
->mItems
[mListIndex
] = nullptr;
208 if (mIsTranslatePoint
) {
209 // Similarly, we must update the tearoff table to remove its (non-owning)
211 sSVGTranslateTearOffTable
.RemoveTearoff(mVal
);
213 // In this case we own mVal
221 bool DOMSVGPoint::IndexIsValid() {
222 nsCOMPtr
<DOMSVGPointList
> pointList
= do_QueryInterface(mOwner
);
223 return mListIndex
< pointList
->InternalList().Length();
227 } // namespace mozilla::dom