Bug 821955 r=longsonr

--HG--
rename : content/svg/content/src/DOMSVGPoint.cpp => content/svg/content/nsISVGPoint.cpp
rename : content/svg/content/src/DOMSVGPoint.cpp => content/svg/content/src/nsISVGPoint.cpp
This commit is contained in:
David Zbarsky 2013-01-16 20:35:24 -05:00
parent b9ec9d66ed
commit 71e0a5342d
13 changed files with 458 additions and 315 deletions

View File

@ -0,0 +1,164 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "SVGPoint.h"
#include "SVGAnimatedPointList.h"
#include "nsSVGElement.h"
#include "nsError.h"
#include "nsContentUtils.h" // NS_ENSURE_FINITE
#include "mozilla/dom/SVGMatrix.h"
#include "mozilla/dom/SVGPointBinding.h"
// See the architecture comment in DOMSVGPointList.h.
using namespace mozilla;
// We could use NS_IMPL_CYCLE_COLLECTION_1, 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_UNLINK_BEGIN(DOMSVGPoint)
// We may not belong to a list, so we must null check tmp->mList.
if (tmp->mList) {
tmp->mList->mItems[tmp->mListIndex] = nullptr;
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mList)
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(mList)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
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_COLLECTING_ADDREF(DOMSVGPoint)
NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGPoint)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGPoint)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(DOMSVGPoint) // pseudo-interface
NS_INTERFACE_MAP_ENTRY(nsISVGPoint)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
float
DOMSVGPoint::X()
{
if (mIsAnimValItem && HasOwner()) {
Element()->FlushAnimations(); // May make HasOwner() == false
}
return HasOwner() ? InternalItem().mX : mPt.mX;
}
void
DOMSVGPoint::SetX(float aX, ErrorResult& rv)
{
if (mIsAnimValItem || mIsReadonly) {
rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
return;
}
if (HasOwner()) {
if (InternalItem().mX == aX) {
return;
}
nsAttrValue emptyOrOldValue = Element()->WillChangePointList();
InternalItem().mX = aX;
Element()->DidChangePointList(emptyOrOldValue);
if (mList->AttrIsAnimating()) {
Element()->AnimationNeedsResample();
}
return;
}
mPt.mX = aX;
}
float
DOMSVGPoint::Y()
{
if (mIsAnimValItem && HasOwner()) {
Element()->FlushAnimations(); // May make HasOwner() == false
}
return HasOwner() ? InternalItem().mY : mPt.mY;
}
void
DOMSVGPoint::SetY(float aY, ErrorResult& rv)
{
if (mIsAnimValItem || mIsReadonly) {
rv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
return;
}
if (HasOwner()) {
if (InternalItem().mY == aY) {
return;
}
nsAttrValue emptyOrOldValue = Element()->WillChangePointList();
InternalItem().mY = aY;
Element()->DidChangePointList(emptyOrOldValue);
if (mList->AttrIsAnimating()) {
Element()->AnimationNeedsResample();
}
return;
}
mPt.mY = aY;
}
already_AddRefed<nsISVGPoint>
DOMSVGPoint::MatrixTransform(dom::SVGMatrix& matrix)
{
float x = HasOwner() ? InternalItem().mX : mPt.mX;
float y = HasOwner() ? InternalItem().mY : mPt.mY;
gfxPoint pt = matrix.Matrix().Transform(gfxPoint(x, y));
nsCOMPtr<nsISVGPoint> newPoint = new DOMSVGPoint(pt);
return newPoint.forget();
}
void
DOMSVGPoint::InsertingIntoList(DOMSVGPointList *aList,
uint32_t aListIndex,
bool aIsAnimValItem)
{
NS_ABORT_IF_FALSE(!HasOwner(), "Inserting item that already has an owner");
mList = aList;
mListIndex = aListIndex;
mIsReadonly = false;
mIsAnimValItem = aIsAnimValItem;
NS_ABORT_IF_FALSE(IndexIsValid(), "Bad index for DOMSVGPoint!");
}
void
DOMSVGPoint::RemovingFromList()
{
mPt = InternalItem();
mList = nullptr;
NS_ABORT_IF_FALSE(!mIsReadonly, "mIsReadonly set for list");
mIsAnimValItem = false;
}
SVGPoint&
DOMSVGPoint::InternalItem()
{
return mList->InternalList().mItems[mListIndex];
}
#ifdef DEBUG
bool
DOMSVGPoint::IndexIsValid()
{
return mListIndex < mList->InternalList().Length();
}
#endif

View File

@ -17,38 +17,6 @@
using namespace mozilla;
// We could use NS_IMPL_CYCLE_COLLECTION_1, 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_UNLINK_BEGIN(DOMSVGPoint)
// We may not belong to a list, so we must null check tmp->mList.
if (tmp->mList) {
tmp->mList->mItems[tmp->mListIndex] = nullptr;
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mList)
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(mList)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
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_COLLECTING_ADDREF(DOMSVGPoint)
NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGPoint)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGPoint)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(DOMSVGPoint) // pseudo-interface
NS_INTERFACE_MAP_ENTRY(nsISVGPoint)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
float
DOMSVGPoint::X()
{
@ -123,42 +91,3 @@ DOMSVGPoint::MatrixTransform(dom::SVGMatrix& matrix)
nsCOMPtr<nsISVGPoint> newPoint = new DOMSVGPoint(pt);
return newPoint.forget();
}
void
DOMSVGPoint::InsertingIntoList(DOMSVGPointList *aList,
uint32_t aListIndex,
bool aIsAnimValItem)
{
NS_ABORT_IF_FALSE(!HasOwner(), "Inserting item that already has an owner");
mList = aList;
mListIndex = aListIndex;
mIsReadonly = false;
mIsAnimValItem = aIsAnimValItem;
NS_ABORT_IF_FALSE(IndexIsValid(), "Bad index for DOMSVGPoint!");
}
void
DOMSVGPoint::RemovingFromList()
{
mPt = InternalItem();
mList = nullptr;
NS_ABORT_IF_FALSE(!mIsReadonly, "mIsReadonly set for list");
mIsAnimValItem = false;
}
SVGPoint&
DOMSVGPoint::InternalItem()
{
return mList->InternalList().mItems[mListIndex];
}
#ifdef DEBUG
bool
DOMSVGPoint::IndexIsValid()
{
return mListIndex < mList->InternalList().Length();
}
#endif

View File

@ -19,17 +19,6 @@
class nsSVGElement;
// We make DOMSVGPoint a pseudo-interface to allow us to QI to it in order to
// check that the objects that scripts pass to DOMSVGPointList methods are
// our *native* point objects.
//
// {d6b6c440-af8d-40ee-856b-02a317cab275}
#define MOZILLA_DOMSVGPOINT_IID \
{ 0xd6b6c440, 0xaf8d, 0x40ee, \
{ 0x85, 0x6b, 0x02, 0xa3, 0x17, 0xca, 0xb2, 0x75 } }
#define MOZ_SVG_LIST_INDEX_BIT_COUNT 30
namespace mozilla {
namespace dom {
@ -53,10 +42,6 @@ class SVGMatrix;
class DOMSVGPoint MOZ_FINAL : public nsISVGPoint
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_DOMSVGPOINT_IID)
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMSVGPoint)
/**
* Generic ctor for DOMSVGPoint objects that are created for an attribute.
*/
@ -64,11 +49,11 @@ public:
uint32_t aListIndex,
bool aIsAnimValItem)
: nsISVGPoint()
, mList(aList)
, mListIndex(aListIndex)
, mIsReadonly(false)
, mIsAnimValItem(aIsAnimValItem)
{
mList = aList;
mListIndex = aListIndex;
mIsAnimValItem = aIsAnimValItem;
// These shifts are in sync with the members.
NS_ABORT_IF_FALSE(aList &&
aListIndex <= MaxListIndex(), "bad arg");
@ -78,10 +63,6 @@ public:
explicit DOMSVGPoint(const DOMSVGPoint *aPt = nullptr)
: nsISVGPoint()
, mList(nullptr)
, mListIndex(0)
, mIsReadonly(false)
, mIsAnimValItem(false)
{
if (aPt) {
mPt = aPt->ToSVGPoint();
@ -90,10 +71,6 @@ public:
DOMSVGPoint(float aX, float aY)
: nsISVGPoint()
, mList(nullptr)
, mListIndex(0)
, mIsReadonly(false)
, mIsAnimValItem(false)
{
mPt.mX = aX;
mPt.mY = aY;
@ -101,10 +78,6 @@ public:
explicit DOMSVGPoint(const gfxPoint &aPt)
: nsISVGPoint()
, mList(nullptr)
, mListIndex(0)
, mIsReadonly(false)
, mIsAnimValItem(false)
{
mPt.mX = float(aPt.x);
mPt.mY = float(aPt.y);
@ -113,15 +86,6 @@ public:
}
virtual ~DOMSVGPoint() {
// Our mList's weak ref to us must be nulled out when we die. If GC has
// unlinked us using the cycle collector code, then that has already
// happened, and mList is null.
if (mList) {
mList->mItems[mListIndex] = nullptr;
}
}
// WebIDL
virtual float X();
virtual void SetX(float aX, ErrorResult& rv);
@ -132,107 +96,17 @@ public:
return mList;
}
/**
* Create an unowned copy of this object. The caller is responsible for the
* first AddRef()!
*/
DOMSVGPoint* Clone() {
nsISVGPoint* Clone() {
return new DOMSVGPoint(this);
}
bool IsInList() const {
return !!mList;
}
/**
* In future, if this class is used for non-list points, this will be
* different to IsInList(). "Owner" here means that the instance has an
* internal counterpart from which it gets its values. (A better name may
* be HasWrappee().)
*/
bool HasOwner() const {
return !!mList;
}
/**
* This method is called to notify this DOM object that it is being inserted
* into a list, and give it the information it needs as a result.
*
* This object MUST NOT already belong to a list when this method is called.
* That's not to say that script can't move these DOM objects between
* lists - it can - it's just that the logic to handle that (and send out
* the necessary notifications) is located elsewhere (in DOMSVGPointList).)
*/
void InsertingIntoList(DOMSVGPointList *aList,
uint32_t aListIndex,
bool aIsAnimValItem);
static uint32_t MaxListIndex() {
return (1U << MOZ_SVG_LIST_INDEX_BIT_COUNT) - 1;
}
/// This method is called to notify this object that its list index changed.
void UpdateListIndex(uint32_t aListIndex) {
mListIndex = aListIndex;
}
/**
* This method is called to notify this DOM object that it is about to be
* removed from its current DOM list so that it can first make a copy of its
* internal counterpart's values. (If it didn't do this, then it would
* "lose" its value on being removed.)
*/
void RemovingFromList();
SVGPoint ToSVGPoint() const {
return HasOwner() ? const_cast<DOMSVGPoint*>(this)->InternalItem() : mPt;
}
bool IsReadonly() const {
return mIsReadonly;
}
void SetReadonly(bool aReadonly) {
mIsReadonly = aReadonly;
}
protected:
nsSVGElement* Element() {
return mList->Element();
}
/**
* Get a reference to the internal SVGPoint list item that this DOM wrapper
* object currently wraps.
*
* To simplify the code we just have this one method for obtaining both
* baseVal and animVal internal items. This means that animVal items don't
* get const protection, but then our setter methods guard against changing
* animVal items.
*/
SVGPoint& InternalItem();
#ifdef DEBUG
bool IndexIsValid();
#endif
nsRefPtr<DOMSVGPointList> mList;
// Bounds for the following are checked in the ctor, so be sure to update
// that if you change the capacity of any of the following.
uint32_t mListIndex:MOZ_SVG_LIST_INDEX_BIT_COUNT;
uint32_t mIsReadonly:1; // uint32_t because MSVC won't pack otherwise
uint32_t mIsAnimValItem:1; // uint32_t because MSVC won't pack otherwise
// The following member is only used when we're not in a list:
SVGPoint mPt;
};
NS_DEFINE_STATIC_IID_ACCESSOR(DOMSVGPoint, MOZILLA_DOMSVGPOINT_IID)
} // namespace mozilla
#undef MOZ_SVG_LIST_INDEX_BIT_COUNT
#endif // MOZILLA_DOMSVGPOINT_H__

View File

@ -19,10 +19,8 @@
// local helper functions
namespace {
using mozilla::DOMSVGPoint;
void
UpdateListIndicesFromIndex(nsTArray<DOMSVGPoint*>& aItemsArray,
UpdateListIndicesFromIndex(nsTArray<mozilla::nsISVGPoint*>& aItemsArray,
uint32_t aStartingIndex)
{
uint32_t length = aItemsArray.Length();
@ -109,10 +107,10 @@ DOMSVGPointList::InternalListWillChangeTo(const SVGPointList& aNewValue)
uint32_t oldLength = mItems.Length();
uint32_t newLength = aNewValue.Length();
if (newLength > DOMSVGPoint::MaxListIndex()) {
if (newLength > nsISVGPoint::MaxListIndex()) {
// It's safe to get out of sync with our internal list as long as we have
// FEWER items than it does.
newLength = DOMSVGPoint::MaxListIndex();
newLength = nsISVGPoint::MaxListIndex();
}
nsRefPtr<DOMSVGPointList> kungFuDeathGrip;
@ -214,11 +212,7 @@ DOMSVGPointList::Initialize(nsISVGPoint& aNewItem, ErrorResult& aError)
// clone of aNewItem, it would actually insert aNewItem. To prevent that
// from happening we have to do the clone here, if necessary.
nsCOMPtr<DOMSVGPoint> domItem = do_QueryInterface(&aNewItem);
if (!domItem) {
aError.Throw(NS_ERROR_DOM_SVG_WRONG_TYPE_ERR);
return nullptr;
}
nsCOMPtr<nsISVGPoint> domItem = &aNewItem;
if (domItem->HasOwner() || domItem->IsReadonly()) {
domItem = domItem->Clone(); // must do this before changing anything!
}
@ -254,16 +248,12 @@ DOMSVGPointList::InsertItemBefore(nsISVGPoint& aNewItem, uint32_t aIndex,
}
aIndex = std::min(aIndex, LengthNoFlush());
if (aIndex >= DOMSVGPoint::MaxListIndex()) {
if (aIndex >= nsISVGPoint::MaxListIndex()) {
aError.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return nullptr;
}
nsCOMPtr<DOMSVGPoint> domItem = do_QueryInterface(&aNewItem);
if (!domItem) {
aError.Throw(NS_ERROR_DOM_SVG_WRONG_TYPE_ERR);
return nullptr;
}
nsCOMPtr<nsISVGPoint> domItem = &aNewItem;
if (domItem->HasOwner() || domItem->IsReadonly()) {
domItem = domItem->Clone(); // must do this before changing anything!
}
@ -310,11 +300,7 @@ DOMSVGPointList::ReplaceItem(nsISVGPoint& aNewItem, uint32_t aIndex,
return nullptr;
}
nsCOMPtr<DOMSVGPoint> domItem = do_QueryInterface(&aNewItem);
if (!domItem) {
aError.Throw(NS_ERROR_DOM_SVG_WRONG_TYPE_ERR);
return nullptr;
}
nsCOMPtr<nsISVGPoint> domItem = &aNewItem;
if (domItem->HasOwner() || domItem->IsReadonly()) {
domItem = domItem->Clone(); // must do this before changing anything!
}
@ -365,7 +351,7 @@ DOMSVGPointList::RemoveItem(uint32_t aIndex, ErrorResult& aError)
// Notify the DOM item of removal *before* modifying the lists so that the
// DOM item can copy its *old* value:
mItems[aIndex]->RemovingFromList();
nsRefPtr<DOMSVGPoint> result = mItems[aIndex];
nsCOMPtr<nsISVGPoint> result = mItems[aIndex];
InternalList().RemoveItem(aIndex);
mItems.RemoveElementAt(aIndex);
@ -408,7 +394,7 @@ DOMSVGPointList::MaybeInsertNullInAnimValListAt(uint32_t aIndex)
NS_ABORT_IF_FALSE(animVal->mItems.Length() == mItems.Length(),
"animVal list not in sync!");
animVal->mItems.InsertElementAt(aIndex, static_cast<DOMSVGPoint*>(nullptr));
animVal->mItems.InsertElementAt(aIndex, static_cast<nsISVGPoint*>(nullptr));
UpdateListIndicesFromIndex(animVal->mItems, aIndex + 1);
}

View File

@ -16,8 +16,6 @@
#include "mozilla/Attributes.h"
#include "mozilla/ErrorResult.h"
class nsIDOMSVGPoint;
namespace mozilla {
class DOMSVGPoint;
@ -52,7 +50,8 @@ class SVGAnimatedPointList;
class DOMSVGPointList MOZ_FINAL : public nsISupports,
public nsWrapperCache
{
friend class DOMSVGPoint;
friend class nsISVGPoint;
friend class mozilla::DOMSVGPoint;
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
@ -208,18 +207,18 @@ private:
SVGAnimatedPointList& InternalAList() const;
/// Creates a DOMSVGPoint for aIndex, if it doesn't already exist.
/// Creates an nsISVGPoint for aIndex, if it doesn't already exist.
void EnsureItemAt(uint32_t aIndex);
void MaybeInsertNullInAnimValListAt(uint32_t aIndex);
void MaybeRemoveItemFromAnimValListAt(uint32_t aIndex);
// Weak refs to our DOMSVGPoint items. The items are friends and take care
// Weak refs to our nsISVGPoint items. The items are friends and take care
// of clearing our pointer to them when they die.
nsTArray<DOMSVGPoint*> mItems;
nsTArray<nsISVGPoint*> mItems;
// Strong ref to our element to keep it alive. We hold this not only for
// ourself, but also for our DOMSVGPoint items too.
// ourself, but also for our nsISVGPoint items too.
nsRefPtr<nsSVGElement> mElement;
bool mIsAnimValList;

View File

@ -35,6 +35,7 @@ CPPSRCS = \
DOMSVGTransformList.cpp \
nsDOMSVGZoomEvent.cpp \
nsDOMSVGEvent.cpp \
nsISVGPoint.cpp \
nsSVGAngle.cpp \
nsSVGBoolean.cpp \
nsSVGClass.cpp \

View File

@ -21,10 +21,8 @@ class SVGPoint
public:
SVGPoint()
#ifdef DEBUG
: mX(0.0f)
, mY(0.0f)
#endif
{}
SVGPoint(float aX, float aY)
@ -65,6 +63,19 @@ public:
}
#endif
void SetX(float aX)
{ mX = aX; }
void SetY(float aY)
{ mY = aY; }
float GetX() const
{ return mX; }
float GetY() const
{ return mY; }
bool operator!=(const SVGPoint &rhs) const {
return mX != rhs.mX || mY != rhs.mY;
}
float mX;
float mY;
};

View File

@ -18,6 +18,7 @@
#include <string.h>
namespace mozilla {
class nsISVGPoint;
/**
* ATTENTION! WARNING! WATCH OUT!!
@ -30,6 +31,7 @@ namespace mozilla {
*/
class SVGPointList
{
friend class mozilla::nsISVGPoint;
friend class SVGAnimatedPointList;
friend class DOMSVGPointList;
friend class DOMSVGPoint;

View File

@ -54,12 +54,12 @@ SVGSVGElement::WrapNode(JSContext *aCx, JSObject *aScope, bool *aTriedToWrap)
return SVGSVGElementBinding::Wrap(aCx, aScope, this, aTriedToWrap);
}
NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(nsSVGTranslatePoint::DOMVal, mElement)
NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(DOMSVGTranslatePoint, mElement)
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGTranslatePoint::DOMVal)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGTranslatePoint::DOMVal)
NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGTranslatePoint)
NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGTranslatePoint)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGTranslatePoint::DOMVal)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGTranslatePoint)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
// We have to qualify nsISVGPoint because NS_GET_IID looks for a class in the
// global namespace
@ -67,39 +67,37 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGTranslatePoint::DOMVal)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
nsresult
nsSVGTranslatePoint::ToDOMVal(SVGSVGElement *aElement,
nsISupports **aResult)
nsISVGPoint*
DOMSVGTranslatePoint::Clone()
{
NS_ADDREF(*aResult = new DOMVal(this, aElement));
return NS_OK;
return new DOMSVGTranslatePoint(this);
}
nsISupports*
nsSVGTranslatePoint::DOMVal::GetParentObject()
DOMSVGTranslatePoint::GetParentObject()
{
return static_cast<nsIDOMSVGSVGElement*>(mElement);
}
void
nsSVGTranslatePoint::DOMVal::SetX(float aValue, ErrorResult& rv)
DOMSVGTranslatePoint::SetX(float aValue, ErrorResult& rv)
{
rv = mElement->SetCurrentTranslate(aValue, mVal->GetY());
rv = mElement->SetCurrentTranslate(aValue, mPt.GetY());
}
void
nsSVGTranslatePoint::DOMVal::SetY(float aValue, ErrorResult& rv)
DOMSVGTranslatePoint::SetY(float aValue, ErrorResult& rv)
{
rv = mElement->SetCurrentTranslate(mVal->GetX(), aValue);
rv = mElement->SetCurrentTranslate(mPt.GetX(), aValue);
}
already_AddRefed<nsISVGPoint>
nsSVGTranslatePoint::DOMVal::MatrixTransform(SVGMatrix& matrix)
DOMSVGTranslatePoint::MatrixTransform(SVGMatrix& matrix)
{
float a = matrix.A(), b = matrix.B(), c = matrix.C();
float d = matrix.D(), e = matrix.E(), f = matrix.F();
float x = mVal->GetX();
float y = mVal->GetY();
float x = mPt.GetX();
float y = mPt.GetY();
nsCOMPtr<nsISVGPoint> point = new DOMSVGPoint(a*x + c*y + e, b*x + d*y + f);
return point.forget();
@ -361,8 +359,7 @@ SVGSVGElement::GetCurrentTranslate(nsISupports * *aCurrentTranslate)
already_AddRefed<nsISVGPoint>
SVGSVGElement::CurrentTranslate()
{
nsCOMPtr<nsISVGPoint> point;
mCurrentTranslate.ToDOMVal(this, getter_AddRefs(point));
nsCOMPtr<nsISVGPoint> point = new DOMSVGTranslatePoint(&mCurrentTranslate, this);
return point.forget();
}
@ -792,7 +789,7 @@ SVGSVGElement::SetCurrentScaleTranslate(float s, float x, float y)
mPreviousTranslate = mCurrentTranslate;
mCurrentScale = s;
mCurrentTranslate = nsSVGTranslatePoint(x, y);
mCurrentTranslate = SVGPoint(x, y);
// now dispatch the appropriate event if we are the root element
nsIDocument* doc = GetCurrentDoc();
@ -964,7 +961,7 @@ SVGSVGElement::UpdateHasChildrenOnlyTransform()
{
bool hasChildrenOnlyTransform =
HasViewBoxOrSyntheticViewBox() ||
(IsRoot() && (mCurrentTranslate != nsSVGTranslatePoint(0.0f, 0.0f) ||
(IsRoot() && (mCurrentTranslate != SVGPoint(0.0f, 0.0f) ||
mCurrentScale != 1.0f));
mHasChildrenOnlyTransform = hasChildrenOnlyTransform;
}

View File

@ -39,57 +39,29 @@ class SVGViewElement;
class SVGSVGElement;
class nsSVGTranslatePoint {
class DOMSVGTranslatePoint MOZ_FINAL : public nsISVGPoint {
public:
nsSVGTranslatePoint()
: mX(0.0f)
, mY(0.0f)
{}
DOMSVGTranslatePoint(SVGPoint* aPt, SVGSVGElement *aElement)
: nsISVGPoint(aPt), mElement(aElement) {}
nsSVGTranslatePoint(float aX, float aY)
: mX(aX)
, mY(aY)
{}
DOMSVGTranslatePoint(DOMSVGTranslatePoint* aPt)
: nsISVGPoint(&aPt->mPt), mElement(aPt->mElement) {}
void SetX(float aX)
{ mX = aX; }
void SetY(float aY)
{ mY = aY; }
float GetX() const
{ return mX; }
float GetY() const
{ return mY; }
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMSVGTranslatePoint)
nsresult ToDOMVal(SVGSVGElement *aElement, nsISupports **aResult);
virtual nsISVGPoint* Clone();
bool operator!=(const nsSVGTranslatePoint &rhs) const {
return mX != rhs.mX || mY != rhs.mY;
}
// WebIDL
virtual float X() { return mPt.GetX(); }
virtual float Y() { return mPt.GetY(); }
virtual void SetX(float aValue, ErrorResult& rv);
virtual void SetY(float aValue, ErrorResult& rv);
virtual already_AddRefed<nsISVGPoint> MatrixTransform(SVGMatrix& matrix);
private:
virtual nsISupports* GetParentObject() MOZ_OVERRIDE;
struct DOMVal MOZ_FINAL : public nsISVGPoint {
DOMVal(nsSVGTranslatePoint* aVal, SVGSVGElement *aElement)
: nsISVGPoint(), mVal(aVal), mElement(aElement) {}
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMVal)
// WebIDL
virtual float X() { return mVal->GetX(); }
virtual float Y() { return mVal->GetY(); }
virtual void SetX(float aValue, ErrorResult& rv);
virtual void SetY(float aValue, ErrorResult& rv);
virtual already_AddRefed<nsISVGPoint> MatrixTransform(SVGMatrix& matrix);
virtual nsISupports* GetParentObject() MOZ_OVERRIDE;
nsSVGTranslatePoint *mVal; // kept alive because it belongs to mElement
nsRefPtr<SVGSVGElement> mElement;
};
float mX;
float mY;
nsRefPtr<SVGSVGElement> mElement;
};
class svgFloatSize {
@ -153,14 +125,14 @@ public:
/**
* Retrieve the value of currentScale and currentTranslate.
*/
const nsSVGTranslatePoint& GetCurrentTranslate() { return mCurrentTranslate; }
const SVGPoint& GetCurrentTranslate() { return mCurrentTranslate; }
float GetCurrentScale() { return mCurrentScale; }
/**
* Retrieve the value of currentScale, currentTranslate.x or
* currentTranslate.y prior to the last change made to any one of them.
*/
const nsSVGTranslatePoint& GetPreviousTranslate() { return mPreviousTranslate; }
const SVGPoint& GetPreviousTranslate() { return mPreviousTranslate; }
float GetPreviousScale() { return mPreviousScale; }
nsSMILTimeContainer* GetTimedDocumentRoot();
@ -412,20 +384,20 @@ private:
// zoom and pan
// IMPORTANT: see the comment in RecordCurrentScaleTranslate before writing
// code to change any of these!
nsSVGTranslatePoint mCurrentTranslate;
float mCurrentScale;
nsSVGTranslatePoint mPreviousTranslate;
float mPreviousScale;
SVGPoint mCurrentTranslate;
float mCurrentScale;
SVGPoint mPreviousTranslate;
float mPreviousScale;
// For outermost <svg> elements created from parsing, animation is started by
// the onload event in accordance with the SVG spec, but for <svg> elements
// created by script or promoted from inner <svg> to outermost <svg> we need
// to manually kick off animation when they are bound to the tree.
bool mStartAnimationOnBindToTree;
bool mImageNeedsTransformInvalidation;
bool mIsPaintingSVGImageElement;
bool mHasChildrenOnlyTransform;
bool mUseCurrentView;
bool mStartAnimationOnBindToTree;
bool mImageNeedsTransformInvalidation;
bool mIsPaintingSVGImageElement;
bool mHasChildrenOnlyTransform;
bool mUseCurrentView;
};
} // namespace dom

View File

@ -54,14 +54,12 @@ nsDOMSVGZoomEvent::nsDOMSVGZoomEvent(nsPresContext* aPresContext,
mNewScale = SVGSVGElem->GetCurrentScale();
mPreviousScale = SVGSVGElem->GetPreviousScale();
const nsSVGTranslatePoint& translate =
SVGSVGElem->GetCurrentTranslate();
const SVGPoint& translate = SVGSVGElem->GetCurrentTranslate();
mNewTranslate =
new DOMSVGPoint(translate.GetX(), translate.GetY());
mNewTranslate->SetReadonly(true);
const nsSVGTranslatePoint& prevTranslate =
SVGSVGElem->GetPreviousTranslate();
const SVGPoint& prevTranslate = SVGSVGElem->GetPreviousTranslate();
mPreviousTranslate =
new DOMSVGPoint(prevTranslate.GetX(), prevTranslate.GetY());
mPreviousTranslate->SetReadonly(true);

View File

@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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 "SVGPoint.h"
#include "SVGAnimatedPointList.h"
#include "nsSVGElement.h"
#include "nsError.h"
#include "nsContentUtils.h" // NS_ENSURE_FINITE
#include "mozilla/dom/SVGMatrix.h"
#include "mozilla/dom/SVGPointBinding.h"
// See the architecture comment in DOMSVGPointList.h.
using namespace mozilla;
// We could use NS_IMPL_CYCLE_COLLECTION_1, 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_UNLINK_BEGIN(nsISVGPoint)
// We may not belong to a list, so we must null check tmp->mList.
if (tmp->mList) {
tmp->mList->mItems[tmp->mListIndex] = nullptr;
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mList)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsISVGPoint)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mList)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsISVGPoint)
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsISVGPoint)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsISVGPoint)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsISVGPoint)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISVGPoint)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
void
nsISVGPoint::InsertingIntoList(DOMSVGPointList *aList,
uint32_t aListIndex,
bool aIsAnimValItem)
{
NS_ABORT_IF_FALSE(!HasOwner(), "Inserting item that already has an owner");
mList = aList;
mListIndex = aListIndex;
mIsReadonly = false;
mIsAnimValItem = aIsAnimValItem;
NS_ABORT_IF_FALSE(IndexIsValid(), "Bad index for DOMSVGPoint!");
}
void
nsISVGPoint::RemovingFromList()
{
mPt = InternalItem();
mList = nullptr;
NS_ABORT_IF_FALSE(!mIsReadonly, "mIsReadonly set for list");
mIsAnimValItem = false;
}
SVGPoint&
nsISVGPoint::InternalItem()
{
return mList->InternalList().mItems[mListIndex];
}
#ifdef DEBUG
bool
nsISVGPoint::IndexIsValid()
{
return mListIndex < mList->InternalList().Length();
}
#endif

View File

@ -9,6 +9,7 @@
#include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h"
#include "mozilla/dom/SVGPointBinding.h"
#include "DOMSVGPointList.h"
class nsSVGElement;
@ -17,6 +18,8 @@ class nsSVGElement;
{ 0xd6b6c440, 0xaf8d, 0x40ee, \
{ 0x85, 0x6b, 0x02, 0xa3, 0x17, 0xca, 0xb2, 0x75 } }
#define MOZ_SVG_LIST_INDEX_BIT_COUNT 30
namespace mozilla {
namespace dom {
@ -27,22 +30,110 @@ class SVGMatrix;
* Class nsISVGPoint
*
* This class creates the DOM objects that wrap internal SVGPoint objects.
* An nsISVGPoint can be either a DOMSVGPoint or a nsSVGTranslatePoint::DOMVal.
* An nsISVGPoint can be either a DOMSVGPoint or a DOMSVGTranslatePoint
*/
class nsISVGPoint : public nsISupports,
public nsWrapperCache
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(MOZILLA_NSISVGPOINT_IID)
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsISVGPoint)
/**
* Generic ctor for DOMSVGPoint objects that are created for an attribute.
*/
explicit nsISVGPoint()
: mList(nullptr)
, mListIndex(0)
, mIsReadonly(false)
, mIsAnimValItem(false)
{
SetIsDOMBinding();
}
explicit nsISVGPoint(SVGPoint* aPt)
: mList(nullptr)
, mListIndex(0)
, mIsReadonly(false)
, mIsAnimValItem(false)
{
SetIsDOMBinding();
mPt.mX = aPt->GetX();
mPt.mY = aPt->GetY();
}
virtual ~nsISVGPoint()
{
// Our mList's weak ref to us must be nulled out when we die. If GC has
// unlinked us using the cycle collector code, then that has already
// happened, and mList is null.
if (mList) {
mList->mItems[mListIndex] = nullptr;
}
}
/**
* Create an unowned copy of this object. The caller is responsible for the
* first AddRef()!
*/
virtual nsISVGPoint* Clone() = 0;
SVGPoint ToSVGPoint() const {
return HasOwner() ? const_cast<nsISVGPoint*>(this)->InternalItem() : mPt;
}
bool IsInList() const {
return !!mList;
}
/**
* In future, if this class is used for non-list points, this will be
* different to IsInList(). "Owner" here means that the instance has an
* internal counterpart from which it gets its values. (A better name may
* be HasWrappee().)
*/
bool HasOwner() const {
return !!mList;
}
/**
* This method is called to notify this DOM object that it is being inserted
* into a list, and give it the information it needs as a result.
*
* This object MUST NOT already belong to a list when this method is called.
* That's not to say that script can't move these DOM objects between
* lists - it can - it's just that the logic to handle that (and send out
* the necessary notifications) is located elsewhere (in DOMSVGPointList).)
*/
void InsertingIntoList(DOMSVGPointList *aList,
uint32_t aListIndex,
bool aIsAnimValItem);
static uint32_t MaxListIndex() {
return (1U << MOZ_SVG_LIST_INDEX_BIT_COUNT) - 1;
}
/// This method is called to notify this object that its list index changed.
void UpdateListIndex(uint32_t aListIndex) {
mListIndex = aListIndex;
}
/**
* This method is called to notify this DOM object that it is about to be
* removed from its current DOM list so that it can first make a copy of its
* internal counterpart's values. (If it didn't do this, then it would
* "lose" its value on being removed.)
*/
void RemovingFromList();
bool IsReadonly() const {
return mIsReadonly;
}
void SetReadonly(bool aReadonly) {
mIsReadonly = aReadonly;
}
// WebIDL
virtual float X() = 0;
virtual void SetX(float aX, ErrorResult& rv) = 0;
@ -54,9 +145,40 @@ public:
{ return dom::SVGPointBinding::Wrap(cx, scope, this, triedToWrap); }
virtual nsISupports* GetParentObject() = 0;
protected:
#ifdef DEBUG
bool IndexIsValid();
#endif
nsRefPtr<DOMSVGPointList> mList;
// Bounds for the following are checked in the ctor, so be sure to update
// that if you change the capacity of any of the following.
uint32_t mListIndex:MOZ_SVG_LIST_INDEX_BIT_COUNT;
uint32_t mIsReadonly:1; // uint32_t because MSVC won't pack otherwise
uint32_t mIsAnimValItem:1; // uint32_t because MSVC won't pack otherwise
/**
* Get a reference to the internal SVGPoint list item that this DOM wrapper
* object currently wraps.
*
* To simplify the code we just have this one method for obtaining both
* baseVal and animVal internal items. This means that animVal items don't
* get const protection, but then our setter methods guard against changing
* animVal items.
*/
SVGPoint& InternalItem();
// The following member is only used when we're not in a list:
SVGPoint mPt;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsISVGPoint, MOZILLA_NSISVGPOINT_IID)
} // namespace mozilla
#undef MOZ_SVG_LIST_INDEX_BIT_COUNT