зеркало из https://github.com/mozilla/gecko-dev.git
233 строки
6.7 KiB
C++
233 строки
6.7 KiB
C++
/* -*- 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 {
|
|
namespace 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
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMSVGPoint, AddRef)
|
|
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMSVGPoint, Release)
|
|
|
|
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 dom
|
|
} // namespace mozilla
|