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 static SVGAttrTearoffTable
<SVGPoint
, DOMSVGPoint
> sSVGTranslateTearOffTable
;
42 // We could use NS_IMPL_CYCLE_COLLECTION(, except that in Unlink() we need to
43 // clear our list's weak ref to us to be safe. (The other option would be to
44 // not unlink and rely on the breaking of the other edges in the cycle, as
45 // NS_SVG_VAL_IMPL_CYCLE_COLLECTION does.)
46 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGPoint
)
48 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGPoint
)
49 tmp
->CleanupWeakRefs();
50 NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner
)
51 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
52 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
54 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGPoint
)
55 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner
)
56 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
58 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGPoint
)
59 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
60 NS_IMPL_CYCLE_COLLECTION_TRACE_END
62 JSObject
* DOMSVGPoint::WrapObject(JSContext
* aCx
,
63 JS::Handle
<JSObject
*> aGivenProto
) {
64 return SVGPoint_Binding::Wrap(aCx
, this, aGivenProto
);
67 float DOMSVGPoint::X() {
68 if (mIsAnimValItem
&& IsInList()) {
69 Element()->FlushAnimations(); // May make IsInList() == false
71 return InternalItem().mX
;
74 void DOMSVGPoint::SetX(float aX
, ErrorResult
& rv
) {
76 rv
.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR
);
80 auto& val
= InternalItem();
86 AutoChangePointListNotifier
listNotifier(this);
87 AutoChangePointNotifier
translateNotifier(this);
92 float DOMSVGPoint::Y() {
93 if (mIsAnimValItem
&& IsInList()) {
94 Element()->FlushAnimations(); // May make IsInList() == false
96 return InternalItem().mY
;
99 void DOMSVGPoint::SetY(float aY
, ErrorResult
& rv
) {
100 if (mIsAnimValItem
) {
101 rv
.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR
);
104 auto& val
= InternalItem();
110 AutoChangePointListNotifier
listNotifier(this);
111 AutoChangePointNotifier
translateNotifier(this);
116 already_AddRefed
<DOMSVGPoint
> DOMSVGPoint::MatrixTransform(
117 const DOMMatrix2DInit
& aMatrix
, ErrorResult
& aRv
) {
118 RefPtr
<DOMMatrixReadOnly
> matrix
=
119 DOMMatrixReadOnly::FromMatrix(GetParentObject(), aMatrix
, aRv
);
123 const auto* matrix2D
= matrix
->GetInternal2D();
124 if (!matrix2D
->IsFinite()) {
125 aRv
.ThrowTypeError
<MSG_NOT_FINITE
>("MatrixTransform matrix");
128 auto pt
= matrix2D
->TransformPoint(InternalItem());
129 return do_AddRef(new DOMSVGPoint(ToPoint(pt
)));
132 void DOMSVGPoint::InsertingIntoList(DOMSVGPointList
* aList
, uint32_t aListIndex
,
133 bool aIsAnimValItem
) {
134 MOZ_RELEASE_ASSERT(!IsInList(), "Inserting item that is already in a list");
135 MOZ_RELEASE_ASSERT(!mIsTranslatePoint
,
136 "Inserting item that is a currentTranslate");
142 mListIndex
= aListIndex
;
143 mIsAnimValItem
= aIsAnimValItem
;
145 MOZ_ASSERT(IndexIsValid(), "Bad index for DOMSVGPoint!");
148 void DOMSVGPoint::RemovingFromList() {
151 "We should start in a list if we're going to be removed from one.");
152 mVal
= new SVGPoint(InternalItem());
154 mIsAnimValItem
= false;
157 SVGPoint
& DOMSVGPoint::InternalItem() {
158 if (nsCOMPtr
<DOMSVGPointList
> pointList
= do_QueryInterface(mOwner
)) {
159 return pointList
->InternalList().mItems
[mListIndex
];
164 already_AddRefed
<DOMSVGPoint
> DOMSVGPoint::GetTranslateTearOff(
165 SVGPoint
* aVal
, SVGSVGElement
* aSVGSVGElement
) {
166 RefPtr
<DOMSVGPoint
> domPoint
= sSVGTranslateTearOffTable
.GetTearoff(aVal
);
168 domPoint
= new DOMSVGPoint(aVal
, aSVGSVGElement
);
169 sSVGTranslateTearOffTable
.AddTearoff(aVal
, domPoint
);
172 return domPoint
.forget();
175 bool DOMSVGPoint::AttrIsAnimating() const {
176 nsCOMPtr
<DOMSVGPointList
> pointList
= do_QueryInterface(mOwner
);
177 return pointList
&& pointList
->AttrIsAnimating();
180 void DOMSVGPoint::DidChangeTranslate() {
181 nsCOMPtr
<SVGSVGElement
> svg
= do_QueryInterface(mOwner
);
183 nsContentUtils::AddScriptRunner(
184 NewRunnableMethod("dom::SVGSVGElement::DidChangeTranslate", svg
,
185 &SVGSVGElement::DidChangeTranslate
));
188 SVGElement
* DOMSVGPoint::Element() {
189 if (nsCOMPtr
<DOMSVGPointList
> pointList
= do_QueryInterface(mOwner
)) {
190 return pointList
->Element();
192 nsCOMPtr
<SVGSVGElement
> svg
= do_QueryInterface(mOwner
);
196 void DOMSVGPoint::CleanupWeakRefs() {
197 // Our mList's weak ref to us must be nulled out when we die (or when we're
198 // cycle collected), so we that don't leave behind a pointer to
199 // free / soon-to-be-free memory.
200 if (nsCOMPtr
<DOMSVGPointList
> pointList
= do_QueryInterface(mOwner
)) {
201 MOZ_ASSERT(pointList
->mItems
[mListIndex
] == this,
202 "Clearing out the wrong list index...?");
203 pointList
->mItems
[mListIndex
] = nullptr;
207 if (mIsTranslatePoint
) {
208 // Similarly, we must update the tearoff table to remove its (non-owning)
210 sSVGTranslateTearOffTable
.RemoveTearoff(mVal
);
212 // In this case we own mVal
220 bool DOMSVGPoint::IndexIsValid() {
221 nsCOMPtr
<DOMSVGPointList
> pointList
= do_QueryInterface(mOwner
);
222 return mListIndex
< pointList
->InternalList().Length();
226 } // namespace mozilla::dom