diff options
Diffstat (limited to 'dom/svg/DOMSVGPoint.cpp')
-rw-r--r-- | dom/svg/DOMSVGPoint.cpp | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/dom/svg/DOMSVGPoint.cpp b/dom/svg/DOMSVGPoint.cpp new file mode 100644 index 0000000000..5cf97c54e4 --- /dev/null +++ b/dom/svg/DOMSVGPoint.cpp @@ -0,0 +1,227 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "DOMSVGPoint.h" + +#include "DOMSVGPointList.h" +#include "gfx2DGlue.h" +#include "nsError.h" +#include "mozilla/dom/DOMMatrix.h" +#include "mozilla/dom/SVGPointBinding.h" + +// See the architecture comment in DOMSVGPointList.h. + +using namespace mozilla::gfx; + +namespace mozilla::dom { + +//---------------------------------------------------------------------- +// Helper class: AutoChangePointNotifier +// +class MOZ_RAII AutoChangePointNotifier { + public: + explicit AutoChangePointNotifier(DOMSVGPoint* aValue) : mValue(aValue) { + MOZ_ASSERT(mValue, "Expecting non-null value"); + } + + ~AutoChangePointNotifier() { + if (mValue->IsTranslatePoint()) { + mValue->DidChangeTranslate(); + } + } + + private: + DOMSVGPoint* const mValue; +}; + +static SVGAttrTearoffTable<SVGPoint, DOMSVGPoint> sSVGTranslateTearOffTable; + +// We could use NS_IMPL_CYCLE_COLLECTION(, except that in Unlink() we need to +// clear our list's weak ref to us to be safe. (The other option would be to +// not unlink and rely on the breaking of the other edges in the cycle, as +// NS_SVG_VAL_IMPL_CYCLE_COLLECTION does.) +NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGPoint) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGPoint) + tmp->CleanupWeakRefs(); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwner) + NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGPoint) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwner) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGPoint) + NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +JSObject* DOMSVGPoint::WrapObject(JSContext* aCx, + JS::Handle<JSObject*> aGivenProto) { + return SVGPoint_Binding::Wrap(aCx, this, aGivenProto); +} + +float DOMSVGPoint::X() { + if (mIsAnimValItem && IsInList()) { + Element()->FlushAnimations(); // May make IsInList() == false + } + return InternalItem().mX; +} + +void DOMSVGPoint::SetX(float aX, ErrorResult& rv) { + if (mIsAnimValItem) { + rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); + return; + } + + auto& val = InternalItem(); + + if (val.mX == aX) { + return; + } + + AutoChangePointListNotifier listNotifier(this); + AutoChangePointNotifier translateNotifier(this); + + val.mX = aX; +} + +float DOMSVGPoint::Y() { + if (mIsAnimValItem && IsInList()) { + Element()->FlushAnimations(); // May make IsInList() == false + } + return InternalItem().mY; +} + +void DOMSVGPoint::SetY(float aY, ErrorResult& rv) { + if (mIsAnimValItem) { + rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR); + return; + } + auto& val = InternalItem(); + + if (val.mY == aY) { + return; + } + + AutoChangePointListNotifier listNotifier(this); + AutoChangePointNotifier translateNotifier(this); + + val.mY = aY; +} + +already_AddRefed<DOMSVGPoint> DOMSVGPoint::MatrixTransform( + const DOMMatrix2DInit& aMatrix, ErrorResult& aRv) { + RefPtr<DOMMatrixReadOnly> matrix = + DOMMatrixReadOnly::FromMatrix(GetParentObject(), aMatrix, aRv); + if (aRv.Failed()) { + return nullptr; + } + const auto* matrix2D = matrix->GetInternal2D(); + if (!matrix2D->IsFinite()) { + aRv.ThrowTypeError<MSG_NOT_FINITE>("MatrixTransform matrix"); + return nullptr; + } + auto pt = matrix2D->TransformPoint(InternalItem()); + RefPtr<DOMSVGPoint> newPoint = new DOMSVGPoint(ToPoint(pt)); + return newPoint.forget(); +} + +void DOMSVGPoint::InsertingIntoList(DOMSVGPointList* aList, uint32_t aListIndex, + bool aIsAnimValItem) { + MOZ_RELEASE_ASSERT(!IsInList(), "Inserting item that is already in a list"); + MOZ_RELEASE_ASSERT(!mIsTranslatePoint, + "Inserting item that is a currentTranslate"); + + delete mVal; + mVal = nullptr; + + mOwner = aList; + mListIndex = aListIndex; + mIsAnimValItem = aIsAnimValItem; + + MOZ_ASSERT(IndexIsValid(), "Bad index for DOMSVGPoint!"); +} + +void DOMSVGPoint::RemovingFromList() { + MOZ_ASSERT( + IsInList(), + "We should start in a list if we're going to be removed from one."); + mVal = new SVGPoint(InternalItem()); + mOwner = nullptr; + mIsAnimValItem = false; +} + +SVGPoint& DOMSVGPoint::InternalItem() { + if (nsCOMPtr<DOMSVGPointList> pointList = do_QueryInterface(mOwner)) { + return pointList->InternalList().mItems[mListIndex]; + } + return *mVal; +} + +already_AddRefed<DOMSVGPoint> DOMSVGPoint::GetTranslateTearOff( + SVGPoint* aVal, SVGSVGElement* aSVGSVGElement) { + RefPtr<DOMSVGPoint> domPoint = sSVGTranslateTearOffTable.GetTearoff(aVal); + if (!domPoint) { + domPoint = new DOMSVGPoint(aVal, aSVGSVGElement); + sSVGTranslateTearOffTable.AddTearoff(aVal, domPoint); + } + + return domPoint.forget(); +} + +bool DOMSVGPoint::AttrIsAnimating() const { + nsCOMPtr<DOMSVGPointList> pointList = do_QueryInterface(mOwner); + return pointList && pointList->AttrIsAnimating(); +} + +void DOMSVGPoint::DidChangeTranslate() { + nsCOMPtr<SVGSVGElement> svg = do_QueryInterface(mOwner); + MOZ_ASSERT(svg); + nsContentUtils::AddScriptRunner( + NewRunnableMethod("dom::SVGSVGElement::DidChangeTranslate", svg, + &SVGSVGElement::DidChangeTranslate)); +} + +SVGElement* DOMSVGPoint::Element() { + if (nsCOMPtr<DOMSVGPointList> pointList = do_QueryInterface(mOwner)) { + return pointList->Element(); + } + nsCOMPtr<SVGSVGElement> svg = do_QueryInterface(mOwner); + return svg; +} + +void DOMSVGPoint::CleanupWeakRefs() { + // Our mList's weak ref to us must be nulled out when we die (or when we're + // cycle collected), so we that don't leave behind a pointer to + // free / soon-to-be-free memory. + if (nsCOMPtr<DOMSVGPointList> pointList = do_QueryInterface(mOwner)) { + MOZ_ASSERT(pointList->mItems[mListIndex] == this, + "Clearing out the wrong list index...?"); + pointList->mItems[mListIndex] = nullptr; + } + + if (mVal) { + if (mIsTranslatePoint) { + // Similarly, we must update the tearoff table to remove its (non-owning) + // pointer to mVal. + sSVGTranslateTearOffTable.RemoveTearoff(mVal); + } else { + // In this case we own mVal + delete mVal; + } + mVal = nullptr; + } +} + +#ifdef DEBUG +bool DOMSVGPoint::IndexIsValid() { + nsCOMPtr<DOMSVGPointList> pointList = do_QueryInterface(mOwner); + return mListIndex < pointList->InternalList().Length(); +} +#endif + +} // namespace mozilla::dom |