Merge mozilla-central to autoland on a CLOSED TREE
[gecko.git] / dom / svg / DOMSVGPoint.cpp
blob5cf97c54e459b52fa7a5fe61d7a971a79cdbdddb
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"
11 #include "nsError.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 {
25 public:
26 explicit AutoChangePointNotifier(DOMSVGPoint* aValue) : mValue(aValue) {
27 MOZ_ASSERT(mValue, "Expecting non-null value");
30 ~AutoChangePointNotifier() {
31 if (mValue->IsTranslatePoint()) {
32 mValue->DidChangeTranslate();
36 private:
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) {
75 if (mIsAnimValItem) {
76 rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
77 return;
80 auto& val = InternalItem();
82 if (val.mX == aX) {
83 return;
86 AutoChangePointListNotifier listNotifier(this);
87 AutoChangePointNotifier translateNotifier(this);
89 val.mX = aX;
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);
102 return;
104 auto& val = InternalItem();
106 if (val.mY == aY) {
107 return;
110 AutoChangePointListNotifier listNotifier(this);
111 AutoChangePointNotifier translateNotifier(this);
113 val.mY = aY;
116 already_AddRefed<DOMSVGPoint> DOMSVGPoint::MatrixTransform(
117 const DOMMatrix2DInit& aMatrix, ErrorResult& aRv) {
118 RefPtr<DOMMatrixReadOnly> matrix =
119 DOMMatrixReadOnly::FromMatrix(GetParentObject(), aMatrix, aRv);
120 if (aRv.Failed()) {
121 return nullptr;
123 const auto* matrix2D = matrix->GetInternal2D();
124 if (!matrix2D->IsFinite()) {
125 aRv.ThrowTypeError<MSG_NOT_FINITE>("MatrixTransform matrix");
126 return nullptr;
128 auto pt = matrix2D->TransformPoint(InternalItem());
129 RefPtr<DOMSVGPoint> newPoint = new DOMSVGPoint(ToPoint(pt));
130 return newPoint.forget();
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");
139 delete mVal;
140 mVal = nullptr;
142 mOwner = aList;
143 mListIndex = aListIndex;
144 mIsAnimValItem = aIsAnimValItem;
146 MOZ_ASSERT(IndexIsValid(), "Bad index for DOMSVGPoint!");
149 void DOMSVGPoint::RemovingFromList() {
150 MOZ_ASSERT(
151 IsInList(),
152 "We should start in a list if we're going to be removed from one.");
153 mVal = new SVGPoint(InternalItem());
154 mOwner = nullptr;
155 mIsAnimValItem = false;
158 SVGPoint& DOMSVGPoint::InternalItem() {
159 if (nsCOMPtr<DOMSVGPointList> pointList = do_QueryInterface(mOwner)) {
160 return pointList->InternalList().mItems[mListIndex];
162 return *mVal;
165 already_AddRefed<DOMSVGPoint> DOMSVGPoint::GetTranslateTearOff(
166 SVGPoint* aVal, SVGSVGElement* aSVGSVGElement) {
167 RefPtr<DOMSVGPoint> domPoint = sSVGTranslateTearOffTable.GetTearoff(aVal);
168 if (!domPoint) {
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);
183 MOZ_ASSERT(svg);
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);
194 return svg;
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;
207 if (mVal) {
208 if (mIsTranslatePoint) {
209 // Similarly, we must update the tearoff table to remove its (non-owning)
210 // pointer to mVal.
211 sSVGTranslateTearOffTable.RemoveTearoff(mVal);
212 } else {
213 // In this case we own mVal
214 delete mVal;
216 mVal = nullptr;
220 #ifdef DEBUG
221 bool DOMSVGPoint::IndexIsValid() {
222 nsCOMPtr<DOMSVGPointList> pointList = do_QueryInterface(mOwner);
223 return mListIndex < pointList->InternalList().Length();
225 #endif
227 } // namespace mozilla::dom