Back out 26f0d590a021, d92e88a18263, 5a2d12a34466 (bug 846995) for not building

CLOSED TREE
This commit is contained in:
Phil Ringnalda 2013-03-19 20:20:38 -07:00
parent 3f78b114b0
commit 3b7e0c1622
25 changed files with 714 additions and 712 deletions

View File

@ -0,0 +1,141 @@
/* -*- 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 "DOMSVGAnimatedTransformList.h"
#include "DOMSVGTransformList.h"
#include "SVGAnimatedTransformList.h"
#include "nsSVGAttrTearoffTable.h"
#include "mozilla/dom/SVGAnimatedTransformListBinding.h"
#include "nsContentUtils.h"
namespace mozilla {
static
nsSVGAttrTearoffTable<SVGAnimatedTransformList,DOMSVGAnimatedTransformList>
sSVGAnimatedTransformListTearoffTable;
NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(DOMSVGAnimatedTransformList, mElement)
NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGAnimatedTransformList)
NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGAnimatedTransformList)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGAnimatedTransformList)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
JSObject*
DOMSVGAnimatedTransformList::WrapObject(JSContext* aCx, JSObject* aScope)
{
return mozilla::dom::SVGAnimatedTransformListBinding::Wrap(aCx, aScope, this);
}
//----------------------------------------------------------------------
already_AddRefed<DOMSVGTransformList>
DOMSVGAnimatedTransformList::BaseVal()
{
if (!mBaseVal) {
mBaseVal = new DOMSVGTransformList(this, InternalAList().GetBaseValue());
}
nsRefPtr<DOMSVGTransformList> baseVal = mBaseVal;
return baseVal.forget();
}
already_AddRefed<DOMSVGTransformList>
DOMSVGAnimatedTransformList::AnimVal()
{
if (!mAnimVal) {
mAnimVal = new DOMSVGTransformList(this, InternalAList().GetAnimValue());
}
nsRefPtr<DOMSVGTransformList> animVal = mAnimVal;
return animVal.forget();
}
/* static */ already_AddRefed<DOMSVGAnimatedTransformList>
DOMSVGAnimatedTransformList::GetDOMWrapper(SVGAnimatedTransformList *aList,
nsSVGElement *aElement)
{
nsRefPtr<DOMSVGAnimatedTransformList> wrapper =
sSVGAnimatedTransformListTearoffTable.GetTearoff(aList);
if (!wrapper) {
wrapper = new DOMSVGAnimatedTransformList(aElement);
sSVGAnimatedTransformListTearoffTable.AddTearoff(aList, wrapper);
}
return wrapper.forget();
}
/* static */ DOMSVGAnimatedTransformList*
DOMSVGAnimatedTransformList::GetDOMWrapperIfExists(
SVGAnimatedTransformList *aList)
{
return sSVGAnimatedTransformListTearoffTable.GetTearoff(aList);
}
DOMSVGAnimatedTransformList::~DOMSVGAnimatedTransformList()
{
// Script no longer has any references to us, to our base/animVal objects, or
// to any of their list items.
sSVGAnimatedTransformListTearoffTable.RemoveTearoff(&InternalAList());
}
void
DOMSVGAnimatedTransformList::InternalBaseValListWillChangeLengthTo(
uint32_t aNewLength)
{
// When the number of items in our internal counterpart's baseVal changes,
// we MUST keep our baseVal in sync. If we don't, script will either see a
// list that is too short and be unable to access indexes that should be
// valid, or else, MUCH WORSE, script will see a list that is too long and be
// able to access "items" at indexes that are out of bounds (read/write to
// bad memory)!!
nsRefPtr<DOMSVGAnimatedTransformList> kungFuDeathGrip;
if (mBaseVal) {
if (aNewLength < mBaseVal->LengthNoFlush()) {
// InternalListLengthWillChange might clear last reference to |this|.
// Retain a temporary reference to keep from dying before returning.
kungFuDeathGrip = this;
}
mBaseVal->InternalListLengthWillChange(aNewLength);
}
// If our attribute is not animating, then our animVal mirrors our baseVal
// and we must sync its length too. (If our attribute is animating, then the
// SMIL engine takes care of calling InternalAnimValListWillChangeLengthTo()
// if necessary.)
if (!IsAnimating()) {
InternalAnimValListWillChangeLengthTo(aNewLength);
}
}
void
DOMSVGAnimatedTransformList::InternalAnimValListWillChangeLengthTo(
uint32_t aNewLength)
{
if (mAnimVal) {
mAnimVal->InternalListLengthWillChange(aNewLength);
}
}
bool
DOMSVGAnimatedTransformList::IsAnimating() const
{
return InternalAList().IsAnimating();
}
SVGAnimatedTransformList&
DOMSVGAnimatedTransformList::InternalAList()
{
return *mElement->GetAnimatedTransformList();
}
const SVGAnimatedTransformList&
DOMSVGAnimatedTransformList::InternalAList() const
{
return *mElement->GetAnimatedTransformList();
}
} // namespace mozilla

View File

@ -0,0 +1,130 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
* 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/. */
#ifndef MOZILLA_DOMSVGANIMATEDTRANSFORMLIST_H__
#define MOZILLA_DOMSVGANIMATEDTRANSFORMLIST_H__
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsSVGElement.h"
#include "nsWrapperCache.h"
#include "mozilla/Attributes.h"
namespace mozilla {
class DOMSVGTransformList;
class SVGAnimatedTransformList;
/**
* Class DOMSVGAnimatedTransformList
*
* This class is used to create the DOM tearoff objects that wrap internal
* SVGAnimatedTransformList objects.
*
* See the architecture comment in DOMSVGAnimatedLengthList.h (that's
* LENGTH list). The comment for that class largly applies to this one too
* and will go a long way to helping you understand the architecture here.
*
* This class is strongly intertwined with DOMSVGTransformList and
* DOMSVGTransform.
* Our DOMSVGTransformList base and anim vals are friends and take care of
* nulling out our pointers to them when they die (making our pointers to them
* true weak refs).
*/
class DOMSVGAnimatedTransformList MOZ_FINAL : public nsISupports,
public nsWrapperCache
{
friend class DOMSVGTransformList;
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMSVGAnimatedTransformList)
/**
* Factory method to create and return a DOMSVGAnimatedTransformList wrapper
* for a given internal SVGAnimatedTransformList object. The factory takes
* care of caching the object that it returns so that the same object can be
* returned for the given SVGAnimatedTransformList each time it is requested.
* The cached object is only removed from the cache when it is destroyed due
* to there being no more references to it or to any of its descendant
* objects. If that happens, any subsequent call requesting the DOM wrapper
* for the SVGAnimatedTransformList will naturally result in a new
* DOMSVGAnimatedTransformList being returned.
*/
static already_AddRefed<DOMSVGAnimatedTransformList>
GetDOMWrapper(SVGAnimatedTransformList *aList, nsSVGElement *aElement);
/**
* This method returns the DOMSVGAnimatedTransformList wrapper for an internal
* SVGAnimatedTransformList object if it currently has a wrapper. If it does
* not, then nullptr is returned.
*/
static DOMSVGAnimatedTransformList*
GetDOMWrapperIfExists(SVGAnimatedTransformList *aList);
/**
* Called by internal code to notify us when we need to sync the length of
* our baseVal DOM list with its internal list. This is called just prior to
* the length of the internal baseVal list being changed so that any DOM list
* items that need to be removed from the DOM list can first get their values
* from their internal counterpart.
*
* The only time this method could fail is on OOM when trying to increase the
* length of the DOM list. If that happens then this method simply clears the
* list and returns. Callers just proceed as normal, and we simply accept
* that the DOM list will be empty (until successfully set to a new value).
*/
void InternalBaseValListWillChangeLengthTo(uint32_t aNewLength);
void InternalAnimValListWillChangeLengthTo(uint32_t aNewLength);
/**
* Returns true if our attribute is animating (in which case our animVal is
* not simply a mirror of our baseVal).
*/
bool IsAnimating() const;
// WebIDL
nsSVGElement* GetParentObject() const { return mElement; }
virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope) MOZ_OVERRIDE;
// These aren't weak refs because mBaseVal and mAnimVal are weak
already_AddRefed<DOMSVGTransformList> BaseVal();
already_AddRefed<DOMSVGTransformList> AnimVal();
private:
/**
* Only our static GetDOMWrapper() factory method may create objects of our
* type.
*/
explicit DOMSVGAnimatedTransformList(nsSVGElement *aElement)
: mBaseVal(nullptr)
, mAnimVal(nullptr)
, mElement(aElement)
{
SetIsDOMBinding();
}
~DOMSVGAnimatedTransformList();
/// Get a reference to this DOM wrapper object's internal counterpart.
SVGAnimatedTransformList& InternalAList();
const SVGAnimatedTransformList& InternalAList() const;
// Weak refs to our DOMSVGTransformList baseVal/animVal objects. These objects
// are friends and take care of clearing these pointers when they die, making
// these true weak references.
DOMSVGTransformList *mBaseVal;
DOMSVGTransformList *mAnimVal;
// Strong ref to our element to keep it alive. We hold this not only for
// ourself, but also for our base/animVal and all of their items.
nsRefPtr<nsSVGElement> mElement;
};
} // namespace mozilla
#endif // MOZILLA_DOMSVGANIMATEDTRANSFORMLIST_H__

View File

@ -6,10 +6,10 @@
#include "DOMSVGTransform.h"
#include "mozilla/dom/SVGMatrix.h"
#include "SVGAnimatedTransformList.h"
#include "nsError.h"
#include "nsContentUtils.h"
#include "nsAttrValueInlines.h"
#include "nsSVGAnimatedTransformList.h"
#include "nsSVGAttrTearoffTable.h"
#include "mozilla/dom/SVGTransformBinding.h"
@ -292,7 +292,7 @@ DOMSVGTransform::RemovingFromList()
SVGTransform&
DOMSVGTransform::InternalItem()
{
nsSVGAnimatedTransformList *alist = Element()->GetAnimatedTransformList();
SVGAnimatedTransformList *alist = Element()->GetAnimatedTransformList();
return mIsAnimValItem && alist->mAnimVal ?
(*alist->mAnimVal)[mListIndex] :
alist->mBaseVal[mListIndex];
@ -308,7 +308,7 @@ DOMSVGTransform::InternalItem() const
bool
DOMSVGTransform::IndexIsValid()
{
nsSVGAnimatedTransformList *alist = Element()->GetAnimatedTransformList();
SVGAnimatedTransformList *alist = Element()->GetAnimatedTransformList();
return (mIsAnimValItem &&
mListIndex < alist->GetAnimValue().Length()) ||
(!mIsAnimValItem &&

View File

@ -6,7 +6,7 @@
#include "DOMSVGTransformList.h"
#include "DOMSVGTransform.h"
#include "mozilla/dom/SVGMatrix.h"
#include "nsSVGAnimatedTransformList.h"
#include "SVGAnimatedTransformList.h"
#include "nsSVGElement.h"
#include "nsContentUtils.h"
#include "mozilla/dom/SVGTransformListBinding.h"
@ -34,7 +34,7 @@ void UpdateListIndicesFromIndex(
namespace mozilla {
// We could use NS_IMPL_CYCLE_COLLECTION_1, except that in Unlink() we need to
// clear our SVGAnimatedTransformList's weak ref to us to be safe. (The other
// clear our DOMSVGAnimatedTransformList'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(DOMSVGTransformList)
@ -114,7 +114,7 @@ DOMSVGTransformList::InternalListLengthWillChange(uint32_t aNewLength)
SVGTransformList&
DOMSVGTransformList::InternalList() const
{
nsSVGAnimatedTransformList *alist = Element()->GetAnimatedTransformList();
SVGAnimatedTransformList *alist = Element()->GetAnimatedTransformList();
return IsAnimValList() && alist->mAnimVal ?
*alist->mAnimVal :
alist->mBaseVal;

View File

@ -7,7 +7,7 @@
#ifndef MOZILLA_DOMSVGTRANSFORMLIST_H__
#define MOZILLA_DOMSVGTRANSFORMLIST_H__
#include "mozilla/dom/SVGAnimatedTransformList.h"
#include "DOMSVGAnimatedTransformList.h"
#include "nsAutoPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsDebug.h"
@ -33,7 +33,7 @@ class DOMSVGTransform;
* This class is used to create the DOM tearoff objects that wrap internal
* SVGTransformList objects.
*
* See the architecture comment in SVGAnimatedTransformList.h.
* See the architecture comment in DOMSVGAnimatedTransformList.h.
*/
class DOMSVGTransformList MOZ_FINAL : public nsISupports,
public nsWrapperCache
@ -44,7 +44,7 @@ public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMSVGTransformList)
DOMSVGTransformList(dom::SVGAnimatedTransformList *aAList,
DOMSVGTransformList(DOMSVGAnimatedTransformList *aAList,
const SVGTransformList &aInternalList)
: mAList(aAList)
{
@ -162,7 +162,7 @@ private:
// of clearing our pointer to them when they die.
nsTArray<DOMSVGTransform*> mItems;
nsRefPtr<dom::SVGAnimatedTransformList> mAList;
nsRefPtr<DOMSVGAnimatedTransformList> mAList;
};
} // namespace mozilla

View File

@ -19,6 +19,7 @@ endif # !_MSC_VER
CPPSRCS = \
DOMSVGAnimatedLengthList.cpp \
DOMSVGAnimatedNumberList.cpp \
DOMSVGAnimatedTransformList.cpp \
DOMSVGLength.cpp \
DOMSVGLengthList.cpp \
DOMSVGNumber.cpp \
@ -33,7 +34,6 @@ CPPSRCS = \
nsDOMSVGZoomEvent.cpp \
nsISVGPoint.cpp \
nsSVGAngle.cpp \
nsSVGAnimatedTransformList.cpp \
nsSVGBoolean.cpp \
nsSVGClass.cpp \
nsSVGDataParser.cpp \
@ -156,7 +156,6 @@ include $(topsrcdir)/config/config.mk
FORCE_STATIC_LIB = 1
EXPORTS = \
nsSVGAnimatedTransformList.h \
nsSVGClass.h \
nsSVGElement.h \
nsSVGFeatures.h \
@ -174,7 +173,6 @@ EXPORTS_mozilla/dom = \
SVGAnimatedAngle.h \
SVGAnimatedBoolean.h \
SVGAnimatedLength.h \
SVGAnimatedTransformList.h \
SVGAnimateElement.h \
SVGAnimateTransformElement.h \
SVGAnimateMotionElement.h \

View File

@ -3,136 +3,318 @@
* 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 "mozilla/dom/SVGAnimatedTransformList.h"
#include "DOMSVGTransformList.h"
#include "nsSVGAnimatedTransformList.h"
#include "nsSVGAttrTearoffTable.h"
#include "mozilla/dom/SVGAnimatedTransformListBinding.h"
#include "nsContentUtils.h"
#include "SVGAnimatedTransformList.h"
#include "DOMSVGAnimatedTransformList.h"
#include "mozilla/dom/SVGAnimationElement.h"
#include "nsSMILValue.h"
#include "prdtoa.h"
#include "SVGContentUtils.h"
#include "SVGTransform.h"
#include "SVGTransformListSMILType.h"
namespace mozilla {
namespace dom {
static
nsSVGAttrTearoffTable<nsSVGAnimatedTransformList, SVGAnimatedTransformList>
sSVGAnimatedTransformListTearoffTable;
NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(SVGAnimatedTransformList, mElement)
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(SVGAnimatedTransformList, AddRef)
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(SVGAnimatedTransformList, Release)
JSObject*
SVGAnimatedTransformList::WrapObject(JSContext* aCx, JSObject* aScope)
nsresult
SVGAnimatedTransformList::SetBaseValueString(const nsAString& aValue)
{
return SVGAnimatedTransformListBinding::Wrap(aCx, aScope, this);
}
//----------------------------------------------------------------------
already_AddRefed<DOMSVGTransformList>
SVGAnimatedTransformList::BaseVal()
{
if (!mBaseVal) {
mBaseVal = new DOMSVGTransformList(this, InternalAList().GetBaseValue());
SVGTransformList newBaseValue;
nsresult rv = newBaseValue.SetValueFromString(aValue);
if (NS_FAILED(rv)) {
return rv;
}
nsRefPtr<DOMSVGTransformList> baseVal = mBaseVal;
return baseVal.forget();
DOMSVGAnimatedTransformList *domWrapper =
DOMSVGAnimatedTransformList::GetDOMWrapperIfExists(this);
if (domWrapper) {
// We must send this notification *before* changing mBaseVal! If the length
// of our baseVal is being reduced, our baseVal's DOM wrapper list may have
// to remove DOM items from itself, and any removed DOM items need to copy
// their internal counterpart values *before* we change them.
//
domWrapper->InternalBaseValListWillChangeLengthTo(newBaseValue.Length());
}
// We don't need to call DidChange* here - we're only called by
// nsSVGElement::ParseAttribute under Element::SetAttr,
// which takes care of notifying.
rv = mBaseVal.CopyFrom(newBaseValue);
if (NS_FAILED(rv) && domWrapper) {
// Attempting to increase mBaseVal's length failed - reduce domWrapper
// back to the same length:
domWrapper->InternalBaseValListWillChangeLengthTo(mBaseVal.Length());
} else {
mIsAttrSet = true;
}
return rv;
}
already_AddRefed<DOMSVGTransformList>
SVGAnimatedTransformList::AnimVal()
void
SVGAnimatedTransformList::ClearBaseValue()
{
DOMSVGAnimatedTransformList *domWrapper =
DOMSVGAnimatedTransformList::GetDOMWrapperIfExists(this);
if (domWrapper) {
// We must send this notification *before* changing mBaseVal! (See above.)
domWrapper->InternalBaseValListWillChangeLengthTo(0);
}
mBaseVal.Clear();
mIsAttrSet = false;
// Caller notifies
}
nsresult
SVGAnimatedTransformList::SetAnimValue(const SVGTransformList& aValue,
nsSVGElement *aElement)
{
DOMSVGAnimatedTransformList *domWrapper =
DOMSVGAnimatedTransformList::GetDOMWrapperIfExists(this);
if (domWrapper) {
// A new animation may totally change the number of items in the animVal
// list, replacing what was essentially a mirror of the baseVal list, or
// else replacing and overriding an existing animation. When this happens
// we must try and keep our animVal's DOM wrapper in sync (see the comment
// in DOMSVGAnimatedTransformList::InternalBaseValListWillChangeLengthTo).
//
// It's not possible for us to reliably distinguish between calls to this
// method that are setting a new sample for an existing animation, and
// calls that are setting the first sample of an animation that will
// override an existing animation. Happily it's cheap to just blindly
// notify our animVal's DOM wrapper of its internal counterpart's new value
// each time this method is called, so that's what we do.
//
// Note that we must send this notification *before* setting or changing
// mAnimVal! (See the comment in SetBaseValueString above.)
//
domWrapper->InternalAnimValListWillChangeLengthTo(aValue.Length());
}
if (!mAnimVal) {
mAnimVal = new DOMSVGTransformList(this, InternalAList().GetAnimValue());
mAnimVal = new SVGTransformList();
}
nsRefPtr<DOMSVGTransformList> animVal = mAnimVal;
return animVal.forget();
}
/* static */ already_AddRefed<SVGAnimatedTransformList>
SVGAnimatedTransformList::GetDOMWrapper(nsSVGAnimatedTransformList *aList,
nsSVGElement *aElement)
{
nsRefPtr<SVGAnimatedTransformList> wrapper =
sSVGAnimatedTransformListTearoffTable.GetTearoff(aList);
if (!wrapper) {
wrapper = new SVGAnimatedTransformList(aElement);
sSVGAnimatedTransformListTearoffTable.AddTearoff(aList, wrapper);
nsresult rv = mAnimVal->CopyFrom(aValue);
if (NS_FAILED(rv)) {
// OOM. We clear the animation, and, importantly, ClearAnimValue() ensures
// that mAnimVal and its DOM wrapper (if any) will have the same length!
ClearAnimValue(aElement);
return rv;
}
return wrapper.forget();
}
/* static */ SVGAnimatedTransformList*
SVGAnimatedTransformList::GetDOMWrapperIfExists(
nsSVGAnimatedTransformList *aList)
{
return sSVGAnimatedTransformListTearoffTable.GetTearoff(aList);
}
SVGAnimatedTransformList::~SVGAnimatedTransformList()
{
// Script no longer has any references to us, to our base/animVal objects, or
// to any of their list items.
sSVGAnimatedTransformListTearoffTable.RemoveTearoff(&InternalAList());
aElement->DidAnimateTransformList();
return NS_OK;
}
void
SVGAnimatedTransformList::InternalBaseValListWillChangeLengthTo(
uint32_t aNewLength)
SVGAnimatedTransformList::ClearAnimValue(nsSVGElement *aElement)
{
// When the number of items in our internal counterpart's baseVal changes,
// we MUST keep our baseVal in sync. If we don't, script will either see a
// list that is too short and be unable to access indexes that should be
// valid, or else, MUCH WORSE, script will see a list that is too long and be
// able to access "items" at indexes that are out of bounds (read/write to
// bad memory)!!
nsRefPtr<SVGAnimatedTransformList> kungFuDeathGrip;
if (mBaseVal) {
if (aNewLength < mBaseVal->LengthNoFlush()) {
// InternalListLengthWillChange might clear last reference to |this|.
// Retain a temporary reference to keep from dying before returning.
kungFuDeathGrip = this;
}
mBaseVal->InternalListLengthWillChange(aNewLength);
}
// If our attribute is not animating, then our animVal mirrors our baseVal
// and we must sync its length too. (If our attribute is animating, then the
// SMIL engine takes care of calling InternalAnimValListWillChangeLengthTo()
// if necessary.)
if (!IsAnimating()) {
InternalAnimValListWillChangeLengthTo(aNewLength);
}
}
void
SVGAnimatedTransformList::InternalAnimValListWillChangeLengthTo(
uint32_t aNewLength)
{
if (mAnimVal) {
mAnimVal->InternalListLengthWillChange(aNewLength);
DOMSVGAnimatedTransformList *domWrapper =
DOMSVGAnimatedTransformList::GetDOMWrapperIfExists(this);
if (domWrapper) {
// When all animation ends, animVal simply mirrors baseVal, which may have
// a different number of items to the last active animated value. We must
// keep the length of our animVal's DOM wrapper list in sync, and again we
// must do that before touching mAnimVal. See comments above.
//
domWrapper->InternalAnimValListWillChangeLengthTo(mBaseVal.Length());
}
mAnimVal = nullptr;
aElement->DidAnimateTransformList();
}
bool
SVGAnimatedTransformList::IsAnimating() const
SVGAnimatedTransformList::IsExplicitlySet() const
{
return InternalAList().IsAnimating();
// Like other methods of this name, we need to know when a transform value has
// been explicitly set.
//
// There are three ways an animated list can become set:
// 1) Markup -- we set mIsAttrSet to true on any successful call to
// SetBaseValueString and clear it on ClearBaseValue (as called by
// nsSVGElement::UnsetAttr or a failed nsSVGElement::ParseAttribute)
// 2) DOM call -- simply fetching the baseVal doesn't mean the transform value
// has been set. It is set if that baseVal has one or more transforms in
// the list.
// 3) Animation -- which will cause the mAnimVal member to be allocated
return mIsAttrSet || !mBaseVal.IsEmpty() || mAnimVal;
}
nsSVGAnimatedTransformList&
SVGAnimatedTransformList::InternalAList()
nsISMILAttr*
SVGAnimatedTransformList::ToSMILAttr(nsSVGElement* aSVGElement)
{
return *mElement->GetAnimatedTransformList();
return new SMILAnimatedTransformList(this, aSVGElement);
}
const nsSVGAnimatedTransformList&
SVGAnimatedTransformList::InternalAList() const
nsresult
SVGAnimatedTransformList::SMILAnimatedTransformList::ValueFromString(
const nsAString& aStr,
const dom::SVGAnimationElement* aSrcElement,
nsSMILValue& aValue,
bool& aPreventCachingOfSandwich) const
{
return *mElement->GetAnimatedTransformList();
NS_ENSURE_TRUE(aSrcElement, NS_ERROR_FAILURE);
NS_ABORT_IF_FALSE(aValue.IsNull(),
"aValue should have been cleared before calling ValueFromString");
const nsAttrValue* typeAttr = aSrcElement->GetAnimAttr(nsGkAtoms::type);
const nsIAtom* transformType = nsGkAtoms::translate; // default val
if (typeAttr) {
if (typeAttr->Type() != nsAttrValue::eAtom) {
// Recognized values of |type| are parsed as an atom -- so if we have
// something other than an atom, then we know already our |type| is
// invalid.
return NS_ERROR_FAILURE;
}
transformType = typeAttr->GetAtomValue();
}
ParseValue(aStr, transformType, aValue);
aPreventCachingOfSandwich = false;
return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK;
}
void
SVGAnimatedTransformList::SMILAnimatedTransformList::ParseValue(
const nsAString& aSpec,
const nsIAtom* aTransformType,
nsSMILValue& aResult)
{
NS_ABORT_IF_FALSE(aResult.IsNull(), "Unexpected type for SMIL value");
// nsSVGSMILTransform constructor should be expecting array with 3 params
PR_STATIC_ASSERT(SVGTransformSMILData::NUM_SIMPLE_PARAMS == 3);
float params[3] = { 0.f };
int32_t numParsed = ParseParameterList(aSpec, params, 3);
uint16_t transformType;
if (aTransformType == nsGkAtoms::translate) {
// tx [ty=0]
if (numParsed != 1 && numParsed != 2)
return;
transformType = SVG_TRANSFORM_TRANSLATE;
} else if (aTransformType == nsGkAtoms::scale) {
// sx [sy=sx]
if (numParsed != 1 && numParsed != 2)
return;
if (numParsed == 1) {
params[1] = params[0];
}
transformType = SVG_TRANSFORM_SCALE;
} else if (aTransformType == nsGkAtoms::rotate) {
// r [cx=0 cy=0]
if (numParsed != 1 && numParsed != 3)
return;
transformType = SVG_TRANSFORM_ROTATE;
} else if (aTransformType == nsGkAtoms::skewX) {
// x-angle
if (numParsed != 1)
return;
transformType = SVG_TRANSFORM_SKEWX;
} else if (aTransformType == nsGkAtoms::skewY) {
// y-angle
if (numParsed != 1)
return;
transformType = SVG_TRANSFORM_SKEWY;
} else {
return;
}
nsSMILValue val(&SVGTransformListSMILType::sSingleton);
SVGTransformSMILData transform(transformType, params);
if (NS_FAILED(SVGTransformListSMILType::AppendTransform(transform, val))) {
return; // OOM
}
// Success! Populate our outparam with parsed value.
aResult.Swap(val);
}
namespace
{
inline void
SkipWsp(nsACString::const_iterator& aIter,
const nsACString::const_iterator& aIterEnd)
{
while (aIter != aIterEnd && IsSVGWhitespace(*aIter))
++aIter;
}
} // end anonymous namespace block
int32_t
SVGAnimatedTransformList::SMILAnimatedTransformList::ParseParameterList(
const nsAString& aSpec,
float* aVars,
int32_t aNVars)
{
NS_ConvertUTF16toUTF8 spec(aSpec);
nsACString::const_iterator start, end;
spec.BeginReading(start);
spec.EndReading(end);
SkipWsp(start, end);
int numArgsFound = 0;
while (start != end) {
char const *arg = start.get();
char *argend;
float f = float(PR_strtod(arg, &argend));
if (arg == argend || argend > end.get() || !NS_finite(f))
return -1;
if (numArgsFound < aNVars) {
aVars[numArgsFound] = f;
}
start.advance(argend - arg);
numArgsFound++;
SkipWsp(start, end);
if (*start == ',') {
++start;
SkipWsp(start, end);
}
}
return numArgsFound;
}
nsSMILValue
SVGAnimatedTransformList::SMILAnimatedTransformList::GetBaseValue() const
{
// To benefit from Return Value Optimization and avoid copy constructor calls
// due to our use of return-by-value, we must return the exact same object
// from ALL return points. This function must only return THIS variable:
nsSMILValue val(&SVGTransformListSMILType::sSingleton);
if (!SVGTransformListSMILType::AppendTransforms(mVal->mBaseVal, val)) {
val = nsSMILValue();
}
return val;
}
nsresult
SVGAnimatedTransformList::SMILAnimatedTransformList::SetAnimValue(
const nsSMILValue& aNewAnimValue)
{
NS_ABORT_IF_FALSE(
aNewAnimValue.mType == &SVGTransformListSMILType::sSingleton,
"Unexpected type to assign animated value");
SVGTransformList animVal;
if (!SVGTransformListSMILType::GetTransforms(aNewAnimValue,
animVal.mItems)) {
return NS_ERROR_FAILURE;
}
return mVal->SetAnimValue(animVal, mElement);
}
void
SVGAnimatedTransformList::SMILAnimatedTransformList::ClearAnimValue()
{
if (mVal->mAnimVal) {
mVal->ClearAnimValue(mElement);
}
}
} // namespace dom
} // namespace mozilla

View File

@ -4,129 +4,123 @@
* 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/. */
#ifndef mozilla_dom_SVGAnimatedTransformList_h
#define mozilla_dom_SVGAnimatedTransformList_h
#ifndef MOZILLA_SVGANIMATEDTRANSFORMLIST_H__
#define MOZILLA_SVGANIMATEDTRANSFORMLIST_H__
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "nsCycleCollectionParticipant.h"
#include "nsSVGElement.h"
#include "nsWrapperCache.h"
#include "mozilla/Attributes.h"
#include "nsISMILAttr.h"
#include "SVGTransformList.h"
class nsIAtom;
class nsSMILValue;
class nsSVGElement;
namespace mozilla {
class DOMSVGTransformList;
class nsSVGAnimatedTransformList;
namespace dom {
class SVGAnimationElement;
}
/**
* Class SVGAnimatedTransformList
*
* This class is used to create the DOM tearoff objects that wrap internal
* nsSVGAnimatedTransformList objects.
* This class is very different to the SVG DOM interface of the same name found
* in the SVG specification. This is a lightweight internal class - see
* DOMSVGAnimatedTransformList for the heavier DOM class that wraps instances of
* this class and implements the SVG specification's SVGAnimatedTransformList
* DOM interface.
*
* See the architecture comment in DOMSVGAnimatedLengthList.h (that's
* LENGTH list). The comment for that class largly applies to this one too
* and will go a long way to helping you understand the architecture here.
*
* This class is strongly intertwined with DOMSVGTransformList and
* DOMSVGTransform.
* Our DOMSVGTransformList base and anim vals are friends and take care of
* nulling out our pointers to them when they die (making our pointers to them
* true weak refs).
* Except where noted otherwise, this class' methods take care of keeping the
* appropriate DOM wrappers in sync (see the comment in
* DOMSVGAnimatedTransformList::InternalBaseValListWillChangeTo) so that their
* consumers don't need to concern themselves with that.
*/
class SVGAnimatedTransformList MOZ_FINAL : public nsWrapperCache
class SVGAnimatedTransformList
{
// friends so that they can get write access to mBaseVal
friend class DOMSVGTransform;
friend class DOMSVGTransformList;
public:
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(SVGAnimatedTransformList)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_NATIVE_CLASS(SVGAnimatedTransformList)
SVGAnimatedTransformList() : mIsAttrSet(false) { }
/**
* Factory method to create and return a SVGAnimatedTransformList wrapper
* for a given internal nsSVGAnimatedTransformList object. The factory takes
* care of caching the object that it returns so that the same object can be
* returned for the given nsSVGAnimatedTransformList each time it is requested.
* The cached object is only removed from the cache when it is destroyed due
* to there being no more references to it or to any of its descendant
* objects. If that happens, any subsequent call requesting the DOM wrapper
* for the nsSVGAnimatedTransformList will naturally result in a new
* SVGAnimatedTransformList being returned.
* Because it's so important that mBaseVal and its DOMSVGTransformList wrapper
* (if any) be kept in sync (see the comment in
* DOMSVGAnimatedTransformList::InternalBaseValListWillChangeTo), this method
* returns a const reference. Only our friend classes may get mutable
* references to mBaseVal.
*/
static already_AddRefed<SVGAnimatedTransformList>
GetDOMWrapper(nsSVGAnimatedTransformList *aList, nsSVGElement *aElement);
const SVGTransformList& GetBaseValue() const {
return mBaseVal;
}
/**
* This method returns the SVGAnimatedTransformList wrapper for an internal
* nsSVGAnimatedTransformList object if it currently has a wrapper. If it does
* not, then nullptr is returned.
*/
static SVGAnimatedTransformList*
GetDOMWrapperIfExists(nsSVGAnimatedTransformList *aList);
nsresult SetBaseValueString(const nsAString& aValue);
/**
* Called by internal code to notify us when we need to sync the length of
* our baseVal DOM list with its internal list. This is called just prior to
* the length of the internal baseVal list being changed so that any DOM list
* items that need to be removed from the DOM list can first get their values
* from their internal counterpart.
*
* The only time this method could fail is on OOM when trying to increase the
* length of the DOM list. If that happens then this method simply clears the
* list and returns. Callers just proceed as normal, and we simply accept
* that the DOM list will be empty (until successfully set to a new value).
*/
void InternalBaseValListWillChangeLengthTo(uint32_t aNewLength);
void InternalAnimValListWillChangeLengthTo(uint32_t aNewLength);
void ClearBaseValue();
/**
* Returns true if our attribute is animating (in which case our animVal is
* not simply a mirror of our baseVal).
*/
bool IsAnimating() const;
const SVGTransformList& GetAnimValue() const {
return mAnimVal ? *mAnimVal : mBaseVal;
}
// WebIDL
nsSVGElement* GetParentObject() const { return mElement; }
virtual JSObject* WrapObject(JSContext* aCx, JSObject* aScope) MOZ_OVERRIDE;
// These aren't weak refs because mBaseVal and mAnimVal are weak
already_AddRefed<DOMSVGTransformList> BaseVal();
already_AddRefed<DOMSVGTransformList> AnimVal();
nsresult SetAnimValue(const SVGTransformList& aNewAnimValue,
nsSVGElement *aElement);
void ClearAnimValue(nsSVGElement *aElement);
bool IsExplicitlySet() const;
bool IsAnimating() const {
return !!mAnimVal;
}
/// Callers own the returned nsISMILAttr
nsISMILAttr* ToSMILAttr(nsSVGElement* aSVGElement);
private:
/**
* Only our static GetDOMWrapper() factory method may create objects of our
* type.
*/
explicit SVGAnimatedTransformList(nsSVGElement *aElement)
: mBaseVal(nullptr)
, mAnimVal(nullptr)
, mElement(aElement)
// mAnimVal is a pointer to allow us to determine if we're being animated or
// not. Making it a non-pointer member and using mAnimVal.IsEmpty() to check
// if we're animating is not an option, since that would break animation *to*
// the empty string (<set to="">).
SVGTransformList mBaseVal;
nsAutoPtr<SVGTransformList> mAnimVal;
bool mIsAttrSet;
struct SMILAnimatedTransformList : public nsISMILAttr
{
SetIsDOMBinding();
}
public:
SMILAnimatedTransformList(SVGAnimatedTransformList* aVal,
nsSVGElement* aSVGElement)
: mVal(aVal)
, mElement(aSVGElement)
{}
~SVGAnimatedTransformList();
// nsISMILAttr methods
virtual nsresult ValueFromString(const nsAString& aStr,
const dom::SVGAnimationElement* aSrcElement,
nsSMILValue& aValue,
bool& aPreventCachingOfSandwich) const;
virtual nsSMILValue GetBaseValue() const;
virtual void ClearAnimValue();
virtual nsresult SetAnimValue(const nsSMILValue& aValue);
/// Get a reference to this DOM wrapper object's internal counterpart.
nsSVGAnimatedTransformList& InternalAList();
const nsSVGAnimatedTransformList& InternalAList() const;
protected:
static void ParseValue(const nsAString& aSpec,
const nsIAtom* aTransformType,
nsSMILValue& aResult);
static int32_t ParseParameterList(const nsAString& aSpec, float* aVars,
int32_t aNVars);
// Weak refs to our DOMSVGTransformList baseVal/animVal objects. These objects
// are friends and take care of clearing these pointers when they die, making
// these true weak references.
DOMSVGTransformList *mBaseVal;
DOMSVGTransformList *mAnimVal;
// Strong ref to our element to keep it alive. We hold this not only for
// ourself, but also for our base/animVal and all of their items.
nsRefPtr<nsSVGElement> mElement;
// These will stay alive because a nsISMILAttr only lives as long
// as the Compositing step, and DOM elements don't get a chance to
// die during that.
SVGAnimatedTransformList* mVal;
nsSVGElement* mElement;
};
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_SVGAnimatedTransformList_h
#endif // MOZILLA_SVGANIMATEDTRANSFORMLIST_H__

View File

@ -156,7 +156,7 @@ SVGFragmentIdentifier::ProcessSVGViewSpec(const nsAString &aViewSpec,
}
preserveAspectRatioFound = true;
} else if (IsMatchingParameter(token, NS_LITERAL_STRING("transform"))) {
nsSVGAnimatedTransformList transforms;
SVGAnimatedTransformList transforms;
if (transformFound ||
NS_FAILED(transforms.SetBaseValueString(params))) {
return false;

View File

@ -5,7 +5,7 @@
#include "mozilla/dom/SVGGradientElement.h"
#include "mozilla/dom/SVGAnimatedTransformList.h"
#include "DOMSVGAnimatedTransformList.h"
#include "mozilla/dom/SVGRadialGradientElementBinding.h"
#include "mozilla/dom/SVGLinearGradientElementBinding.h"
#include "mozilla/Util.h"
@ -89,12 +89,12 @@ SVGGradientElement::GradientUnits()
}
/* readonly attribute SVGAnimatedTransformList gradientTransform; */
already_AddRefed<SVGAnimatedTransformList>
already_AddRefed<DOMSVGAnimatedTransformList>
SVGGradientElement::GradientTransform()
{
// We're creating a DOM wrapper, so we must tell GetAnimatedTransformList
// to allocate the SVGAnimatedTransformList if it hasn't already done so:
return SVGAnimatedTransformList::GetDOMWrapper(
return DOMSVGAnimatedTransformList::GetDOMWrapper(
GetAnimatedTransformList(DO_ALLOCATE), this);
}
@ -190,11 +190,11 @@ SVGLinearGradientElement::Y2()
//----------------------------------------------------------------------
// nsSVGElement methods
nsSVGAnimatedTransformList*
SVGAnimatedTransformList*
SVGGradientElement::GetAnimatedTransformList(uint32_t aFlags)
{
if (!mGradientTransform && (aFlags & DO_ALLOCATE)) {
mGradientTransform = new nsSVGAnimatedTransformList();
mGradientTransform = new SVGAnimatedTransformList();
}
return mGradientTransform;
}

View File

@ -7,11 +7,11 @@
#define __NS_SVGGRADIENTELEMENT_H__
#include "nsIDOMSVGUnitTypes.h"
#include "nsSVGAnimatedTransformList.h"
#include "nsSVGElement.h"
#include "nsSVGLength2.h"
#include "nsSVGEnum.h"
#include "nsSVGString.h"
#include "SVGAnimatedTransformList.h"
static const unsigned short SVG_SPREADMETHOD_UNKNOWN = 0;
static const unsigned short SVG_SPREADMETHOD_PAD = 1;
@ -30,9 +30,10 @@ NS_NewSVGRadialGradientElement(nsIContent** aResult,
already_AddRefed<nsINodeInfo> aNodeInfo);
namespace mozilla {
namespace dom {
class SVGAnimatedTransformList;
class DOMSVGAnimatedTransformList;
namespace dom {
//--------------------- Gradients------------------------
@ -55,7 +56,7 @@ public:
// nsIContent
NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const;
virtual nsSVGAnimatedTransformList*
virtual SVGAnimatedTransformList*
GetAnimatedTransformList(uint32_t aFlags = 0);
virtual nsIAtom* GetTransformListAttrName() const {
return nsGkAtoms::gradientTransform;
@ -63,7 +64,7 @@ public:
// WebIDL
already_AddRefed<nsIDOMSVGAnimatedEnumeration> GradientUnits();
already_AddRefed<SVGAnimatedTransformList> GradientTransform();
already_AddRefed<DOMSVGAnimatedTransformList> GradientTransform();
already_AddRefed<nsIDOMSVGAnimatedEnumeration> SpreadMethod();
already_AddRefed<nsIDOMSVGAnimatedString> Href();
@ -81,7 +82,7 @@ protected:
static StringInfo sStringInfo[1];
// SVGGradientElement values
nsAutoPtr<nsSVGAnimatedTransformList> mGradientTransform;
nsAutoPtr<SVGAnimatedTransformList> mGradientTransform;
};
//---------------------Linear Gradients------------------------

View File

@ -5,12 +5,11 @@
#include "mozilla/Util.h"
#include "DOMSVGAnimatedTransformList.h"
#include "nsCOMPtr.h"
#include "nsGkAtoms.h"
#include "mozilla/dom/SVGAnimatedTransformList.h"
#include "mozilla/dom/SVGPatternElement.h"
#include "mozilla/dom/SVGPatternElementBinding.h"
#include "nsSVGAnimatedTransformList.h"
NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Pattern)
@ -103,12 +102,12 @@ SVGPatternElement::PatternContentUnits()
return mEnumAttributes[PATTERNCONTENTUNITS].ToDOMAnimatedEnum(this);
}
already_AddRefed<SVGAnimatedTransformList>
already_AddRefed<DOMSVGAnimatedTransformList>
SVGPatternElement::PatternTransform()
{
// We're creating a DOM wrapper, so we must tell GetAnimatedTransformList
// to allocate the SVGAnimatedTransformList if it hasn't already done so:
return SVGAnimatedTransformList::GetDOMWrapper(
return DOMSVGAnimatedTransformList::GetDOMWrapper(
GetAnimatedTransformList(DO_ALLOCATE), this);
}
@ -166,11 +165,11 @@ SVGPatternElement::IsAttributeMapped(const nsIAtom* name) const
//----------------------------------------------------------------------
// nsSVGElement methods
nsSVGAnimatedTransformList*
SVGAnimatedTransformList*
SVGPatternElement::GetAnimatedTransformList(uint32_t aFlags)
{
if (!mPatternTransform && (aFlags & DO_ALLOCATE)) {
mPatternTransform = new nsSVGAnimatedTransformList();
mPatternTransform = new SVGAnimatedTransformList();
}
return mPatternTransform;
}

View File

@ -21,9 +21,9 @@ nsresult NS_NewSVGPatternElement(nsIContent **aResult,
already_AddRefed<nsINodeInfo> aNodeInfo);
namespace mozilla {
class DOMSVGAnimatedTransformList;
namespace dom {
class SVGAnimatedTransformList;
typedef nsSVGElement SVGPatternElementBase;
@ -40,6 +40,8 @@ protected:
virtual JSObject* WrapNode(JSContext *cx, JSObject *scope) MOZ_OVERRIDE;
public:
typedef mozilla::SVGAnimatedPreserveAspectRatio SVGAnimatedPreserveAspectRatio;
// interfaces:
NS_DECL_ISUPPORTS_INHERITED
@ -57,7 +59,7 @@ public:
// nsSVGSVGElement methods:
virtual bool HasValidDimensions() const;
virtual nsSVGAnimatedTransformList*
virtual mozilla::SVGAnimatedTransformList*
GetAnimatedTransformList(uint32_t aFlags = 0);
virtual nsIAtom* GetTransformListAttrName() const {
return nsGkAtoms::patternTransform;
@ -68,7 +70,7 @@ public:
already_AddRefed<DOMSVGAnimatedPreserveAspectRatio> PreserveAspectRatio();
already_AddRefed<nsIDOMSVGAnimatedEnumeration> PatternUnits();
already_AddRefed<nsIDOMSVGAnimatedEnumeration> PatternContentUnits();
already_AddRefed<SVGAnimatedTransformList> PatternTransform();
already_AddRefed<DOMSVGAnimatedTransformList> PatternTransform();
already_AddRefed<SVGAnimatedLength> X();
already_AddRefed<SVGAnimatedLength> Y();
already_AddRefed<SVGAnimatedLength> Width();
@ -91,7 +93,7 @@ protected:
nsSVGEnum mEnumAttributes[2];
static EnumInfo sEnumInfo[2];
nsAutoPtr<nsSVGAnimatedTransformList> mPatternTransform;
nsAutoPtr<mozilla::SVGAnimatedTransformList> mPatternTransform;
enum { HREF };
nsSVGString mStringAttributes[1];

View File

@ -25,7 +25,7 @@ namespace mozilla {
*/
class SVGTransformList
{
friend class nsSVGAnimatedTransformList;
friend class SVGAnimatedTransformList;
friend class DOMSVGTransformList;
friend class DOMSVGTransform;

View File

@ -3,10 +3,10 @@
* 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 "mozilla/dom/SVGAnimatedTransformList.h"
#include "mozilla/dom/SVGTransformableElement.h"
#include "mozilla/dom/SVGMatrix.h"
#include "mozilla/dom/SVGSVGElement.h"
#include "DOMSVGAnimatedTransformList.h"
#include "nsContentUtils.h"
#include "nsIDOMMutationEvent.h"
#include "nsIFrame.h"
@ -23,12 +23,12 @@ namespace dom {
NS_IMPL_ISUPPORTS_INHERITED0(SVGTransformableElement, nsSVGElement)
already_AddRefed<SVGAnimatedTransformList>
already_AddRefed<DOMSVGAnimatedTransformList>
SVGTransformableElement::Transform()
{
// We're creating a DOM wrapper, so we must tell GetAnimatedTransformList
// to allocate the SVGAnimatedTransformList if it hasn't already done so:
return SVGAnimatedTransformList::GetDOMWrapper(
return DOMSVGAnimatedTransformList::GetDOMWrapper(
GetAnimatedTransformList(DO_ALLOCATE), this).get();
}
@ -139,11 +139,11 @@ SVGTransformableElement::SetAnimateMotionTransform(const gfxMatrix* aMatrix)
DidAnimateTransformList();
}
nsSVGAnimatedTransformList*
SVGAnimatedTransformList*
SVGTransformableElement::GetAnimatedTransformList(uint32_t aFlags)
{
if (!mTransforms && (aFlags & DO_ALLOCATE)) {
mTransforms = new nsSVGAnimatedTransformList();
mTransforms = new SVGAnimatedTransformList();
}
return mTransforms;
}

View File

@ -6,16 +6,17 @@
#ifndef SVGTransformableElement_h
#define SVGTransformableElement_h
#include "nsSVGAnimatedTransformList.h"
#include "nsSVGElement.h"
#include "gfxMatrix.h"
#include "SVGAnimatedTransformList.h"
class nsIDOMSVGRect;
namespace mozilla {
class DOMSVGAnimatedTransformList;
namespace dom {
class SVGAnimatedTransformList;
class SVGGraphicsElement;
class SVGMatrix;
@ -29,7 +30,7 @@ public:
NS_DECL_ISUPPORTS_INHERITED
// WebIDL
already_AddRefed<SVGAnimatedTransformList> Transform();
already_AddRefed<DOMSVGAnimatedTransformList> Transform();
nsSVGElement* GetNearestViewportElement();
nsSVGElement* GetFarthestViewportElement();
already_AddRefed<nsIDOMSVGRect> GetBBox(ErrorResult& rv);
@ -53,7 +54,7 @@ public:
virtual const gfxMatrix* GetAnimateMotionTransform() const;
virtual void SetAnimateMotionTransform(const gfxMatrix* aMatrix);
virtual nsSVGAnimatedTransformList*
virtual SVGAnimatedTransformList*
GetAnimatedTransformList(uint32_t aFlags = 0);
virtual nsIAtom* GetTransformListAttrName() const {
return nsGkAtoms::transform;
@ -62,7 +63,7 @@ public:
protected:
// nsSVGElement overrides
nsAutoPtr<nsSVGAnimatedTransformList> mTransforms;
nsAutoPtr<SVGAnimatedTransformList> mTransforms;
// XXX maybe move this to property table, to save space on un-animated elems?
nsAutoPtr<gfxMatrix> mAnimateMotionTransform;

View File

@ -1,321 +0,0 @@
/* -*- 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 "nsSVGAnimatedTransformList.h"
#include "mozilla/dom/SVGAnimatedTransformList.h"
#include "mozilla/dom/SVGAnimationElement.h"
#include "nsSMILValue.h"
#include "prdtoa.h"
#include "SVGContentUtils.h"
#include "SVGTransform.h"
#include "SVGTransformListSMILType.h"
namespace mozilla {
using namespace dom;
nsresult
nsSVGAnimatedTransformList::SetBaseValueString(const nsAString& aValue)
{
SVGTransformList newBaseValue;
nsresult rv = newBaseValue.SetValueFromString(aValue);
if (NS_FAILED(rv)) {
return rv;
}
SVGAnimatedTransformList *domWrapper =
SVGAnimatedTransformList::GetDOMWrapperIfExists(this);
if (domWrapper) {
// We must send this notification *before* changing mBaseVal! If the length
// of our baseVal is being reduced, our baseVal's DOM wrapper list may have
// to remove DOM items from itself, and any removed DOM items need to copy
// their internal counterpart values *before* we change them.
//
domWrapper->InternalBaseValListWillChangeLengthTo(newBaseValue.Length());
}
// We don't need to call DidChange* here - we're only called by
// nsSVGElement::ParseAttribute under Element::SetAttr,
// which takes care of notifying.
rv = mBaseVal.CopyFrom(newBaseValue);
if (NS_FAILED(rv) && domWrapper) {
// Attempting to increase mBaseVal's length failed - reduce domWrapper
// back to the same length:
domWrapper->InternalBaseValListWillChangeLengthTo(mBaseVal.Length());
} else {
mIsAttrSet = true;
}
return rv;
}
void
nsSVGAnimatedTransformList::ClearBaseValue()
{
SVGAnimatedTransformList *domWrapper =
SVGAnimatedTransformList::GetDOMWrapperIfExists(this);
if (domWrapper) {
// We must send this notification *before* changing mBaseVal! (See above.)
domWrapper->InternalBaseValListWillChangeLengthTo(0);
}
mBaseVal.Clear();
mIsAttrSet = false;
// Caller notifies
}
nsresult
nsSVGAnimatedTransformList::SetAnimValue(const SVGTransformList& aValue,
nsSVGElement *aElement)
{
SVGAnimatedTransformList *domWrapper =
SVGAnimatedTransformList::GetDOMWrapperIfExists(this);
if (domWrapper) {
// A new animation may totally change the number of items in the animVal
// list, replacing what was essentially a mirror of the baseVal list, or
// else replacing and overriding an existing animation. When this happens
// we must try and keep our animVal's DOM wrapper in sync (see the comment
// in SVGAnimatedTransformList::InternalBaseValListWillChangeLengthTo).
//
// It's not possible for us to reliably distinguish between calls to this
// method that are setting a new sample for an existing animation, and
// calls that are setting the first sample of an animation that will
// override an existing animation. Happily it's cheap to just blindly
// notify our animVal's DOM wrapper of its internal counterpart's new value
// each time this method is called, so that's what we do.
//
// Note that we must send this notification *before* setting or changing
// mAnimVal! (See the comment in SetBaseValueString above.)
//
domWrapper->InternalAnimValListWillChangeLengthTo(aValue.Length());
}
if (!mAnimVal) {
mAnimVal = new SVGTransformList();
}
nsresult rv = mAnimVal->CopyFrom(aValue);
if (NS_FAILED(rv)) {
// OOM. We clear the animation, and, importantly, ClearAnimValue() ensures
// that mAnimVal and its DOM wrapper (if any) will have the same length!
ClearAnimValue(aElement);
return rv;
}
aElement->DidAnimateTransformList();
return NS_OK;
}
void
nsSVGAnimatedTransformList::ClearAnimValue(nsSVGElement *aElement)
{
SVGAnimatedTransformList *domWrapper =
SVGAnimatedTransformList::GetDOMWrapperIfExists(this);
if (domWrapper) {
// When all animation ends, animVal simply mirrors baseVal, which may have
// a different number of items to the last active animated value. We must
// keep the length of our animVal's DOM wrapper list in sync, and again we
// must do that before touching mAnimVal. See comments above.
//
domWrapper->InternalAnimValListWillChangeLengthTo(mBaseVal.Length());
}
mAnimVal = nullptr;
aElement->DidAnimateTransformList();
}
bool
nsSVGAnimatedTransformList::IsExplicitlySet() const
{
// Like other methods of this name, we need to know when a transform value has
// been explicitly set.
//
// There are three ways an animated list can become set:
// 1) Markup -- we set mIsAttrSet to true on any successful call to
// SetBaseValueString and clear it on ClearBaseValue (as called by
// nsSVGElement::UnsetAttr or a failed nsSVGElement::ParseAttribute)
// 2) DOM call -- simply fetching the baseVal doesn't mean the transform value
// has been set. It is set if that baseVal has one or more transforms in
// the list.
// 3) Animation -- which will cause the mAnimVal member to be allocated
return mIsAttrSet || !mBaseVal.IsEmpty() || mAnimVal;
}
nsISMILAttr*
nsSVGAnimatedTransformList::ToSMILAttr(nsSVGElement* aSVGElement)
{
return new SMILAnimatedTransformList(this, aSVGElement);
}
nsresult
nsSVGAnimatedTransformList::SMILAnimatedTransformList::ValueFromString(
const nsAString& aStr,
const dom::SVGAnimationElement* aSrcElement,
nsSMILValue& aValue,
bool& aPreventCachingOfSandwich) const
{
NS_ENSURE_TRUE(aSrcElement, NS_ERROR_FAILURE);
NS_ABORT_IF_FALSE(aValue.IsNull(),
"aValue should have been cleared before calling ValueFromString");
const nsAttrValue* typeAttr = aSrcElement->GetAnimAttr(nsGkAtoms::type);
const nsIAtom* transformType = nsGkAtoms::translate; // default val
if (typeAttr) {
if (typeAttr->Type() != nsAttrValue::eAtom) {
// Recognized values of |type| are parsed as an atom -- so if we have
// something other than an atom, then we know already our |type| is
// invalid.
return NS_ERROR_FAILURE;
}
transformType = typeAttr->GetAtomValue();
}
ParseValue(aStr, transformType, aValue);
aPreventCachingOfSandwich = false;
return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK;
}
void
nsSVGAnimatedTransformList::SMILAnimatedTransformList::ParseValue(
const nsAString& aSpec,
const nsIAtom* aTransformType,
nsSMILValue& aResult)
{
NS_ABORT_IF_FALSE(aResult.IsNull(), "Unexpected type for SMIL value");
// nsSVGSMILTransform constructor should be expecting array with 3 params
PR_STATIC_ASSERT(SVGTransformSMILData::NUM_SIMPLE_PARAMS == 3);
float params[3] = { 0.f };
int32_t numParsed = ParseParameterList(aSpec, params, 3);
uint16_t transformType;
if (aTransformType == nsGkAtoms::translate) {
// tx [ty=0]
if (numParsed != 1 && numParsed != 2)
return;
transformType = SVG_TRANSFORM_TRANSLATE;
} else if (aTransformType == nsGkAtoms::scale) {
// sx [sy=sx]
if (numParsed != 1 && numParsed != 2)
return;
if (numParsed == 1) {
params[1] = params[0];
}
transformType = SVG_TRANSFORM_SCALE;
} else if (aTransformType == nsGkAtoms::rotate) {
// r [cx=0 cy=0]
if (numParsed != 1 && numParsed != 3)
return;
transformType = SVG_TRANSFORM_ROTATE;
} else if (aTransformType == nsGkAtoms::skewX) {
// x-angle
if (numParsed != 1)
return;
transformType = SVG_TRANSFORM_SKEWX;
} else if (aTransformType == nsGkAtoms::skewY) {
// y-angle
if (numParsed != 1)
return;
transformType = SVG_TRANSFORM_SKEWY;
} else {
return;
}
nsSMILValue val(&SVGTransformListSMILType::sSingleton);
SVGTransformSMILData transform(transformType, params);
if (NS_FAILED(SVGTransformListSMILType::AppendTransform(transform, val))) {
return; // OOM
}
// Success! Populate our outparam with parsed value.
aResult.Swap(val);
}
namespace
{
inline void
SkipWsp(nsACString::const_iterator& aIter,
const nsACString::const_iterator& aIterEnd)
{
while (aIter != aIterEnd && IsSVGWhitespace(*aIter))
++aIter;
}
} // end anonymous namespace block
int32_t
nsSVGAnimatedTransformList::SMILAnimatedTransformList::ParseParameterList(
const nsAString& aSpec,
float* aVars,
int32_t aNVars)
{
NS_ConvertUTF16toUTF8 spec(aSpec);
nsACString::const_iterator start, end;
spec.BeginReading(start);
spec.EndReading(end);
SkipWsp(start, end);
int numArgsFound = 0;
while (start != end) {
char const *arg = start.get();
char *argend;
float f = float(PR_strtod(arg, &argend));
if (arg == argend || argend > end.get() || !NS_finite(f))
return -1;
if (numArgsFound < aNVars) {
aVars[numArgsFound] = f;
}
start.advance(argend - arg);
numArgsFound++;
SkipWsp(start, end);
if (*start == ',') {
++start;
SkipWsp(start, end);
}
}
return numArgsFound;
}
nsSMILValue
nsSVGAnimatedTransformList::SMILAnimatedTransformList::GetBaseValue() const
{
// To benefit from Return Value Optimization and avoid copy constructor calls
// due to our use of return-by-value, we must return the exact same object
// from ALL return points. This function must only return THIS variable:
nsSMILValue val(&SVGTransformListSMILType::sSingleton);
if (!SVGTransformListSMILType::AppendTransforms(mVal->mBaseVal, val)) {
val = nsSMILValue();
}
return val;
}
nsresult
nsSVGAnimatedTransformList::SMILAnimatedTransformList::SetAnimValue(
const nsSMILValue& aNewAnimValue)
{
NS_ABORT_IF_FALSE(
aNewAnimValue.mType == &SVGTransformListSMILType::sSingleton,
"Unexpected type to assign animated value");
SVGTransformList animVal;
if (!SVGTransformListSMILType::GetTransforms(aNewAnimValue,
animVal.mItems)) {
return NS_ERROR_FAILURE;
}
return mVal->SetAnimValue(animVal, mElement);
}
void
nsSVGAnimatedTransformList::SMILAnimatedTransformList::ClearAnimValue()
{
if (mVal->mAnimVal) {
mVal->ClearAnimValue(mElement);
}
}
} // namespace mozilla

View File

@ -1,126 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
* 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/. */
#ifndef MOZILLA_SVGANIMATEDTRANSFORMLIST_H__
#define MOZILLA_SVGANIMATEDTRANSFORMLIST_H__
#include "nsAutoPtr.h"
#include "nsISMILAttr.h"
#include "SVGTransformList.h"
class nsIAtom;
class nsSMILValue;
class nsSVGElement;
namespace mozilla {
namespace dom {
class SVGAnimationElement;
}
/**
* Class nsSVGAnimatedTransformList
*
* This class is very different to the SVG DOM interface of the same name found
* in the SVG specification. This is a lightweight internal class - see
* SVGAnimatedTransformList for the heavier DOM class that wraps instances of
* this class and implements the SVG specification's SVGAnimatedTransformList
* DOM interface.
*
* Except where noted otherwise, this class' methods take care of keeping the
* appropriate DOM wrappers in sync (see the comment in
* SVGAnimatedTransformList::InternalBaseValListWillChangeTo) so that their
* consumers don't need to concern themselves with that.
*/
class nsSVGAnimatedTransformList
{
// friends so that they can get write access to mBaseVal
friend class DOMSVGTransform;
friend class DOMSVGTransformList;
public:
nsSVGAnimatedTransformList() : mIsAttrSet(false) { }
/**
* Because it's so important that mBaseVal and its DOMSVGTransformList wrapper
* (if any) be kept in sync (see the comment in
* SVGAnimatedTransformList::InternalBaseValListWillChangeTo), this method
* returns a const reference. Only our friend classes may get mutable
* references to mBaseVal.
*/
const SVGTransformList& GetBaseValue() const {
return mBaseVal;
}
nsresult SetBaseValueString(const nsAString& aValue);
void ClearBaseValue();
const SVGTransformList& GetAnimValue() const {
return mAnimVal ? *mAnimVal : mBaseVal;
}
nsresult SetAnimValue(const SVGTransformList& aNewAnimValue,
nsSVGElement *aElement);
void ClearAnimValue(nsSVGElement *aElement);
bool IsExplicitlySet() const;
bool IsAnimating() const {
return !!mAnimVal;
}
/// Callers own the returned nsISMILAttr
nsISMILAttr* ToSMILAttr(nsSVGElement* aSVGElement);
private:
// mAnimVal is a pointer to allow us to determine if we're being animated or
// not. Making it a non-pointer member and using mAnimVal.IsEmpty() to check
// if we're animating is not an option, since that would break animation *to*
// the empty string (<set to="">).
SVGTransformList mBaseVal;
nsAutoPtr<SVGTransformList> mAnimVal;
bool mIsAttrSet;
struct SMILAnimatedTransformList : public nsISMILAttr
{
public:
SMILAnimatedTransformList(nsSVGAnimatedTransformList* aVal,
nsSVGElement* aSVGElement)
: mVal(aVal)
, mElement(aSVGElement)
{}
// nsISMILAttr methods
virtual nsresult ValueFromString(const nsAString& aStr,
const dom::SVGAnimationElement* aSrcElement,
nsSMILValue& aValue,
bool& aPreventCachingOfSandwich) const;
virtual nsSMILValue GetBaseValue() const;
virtual void ClearAnimValue();
virtual nsresult SetAnimValue(const nsSMILValue& aValue);
protected:
static void ParseValue(const nsAString& aSpec,
const nsIAtom* aTransformType,
nsSMILValue& aResult);
static int32_t ParseParameterList(const nsAString& aSpec, float* aVars,
int32_t aNVars);
// These will stay alive because a nsISMILAttr only lives as long
// as the Compositing step, and DOM elements don't get a chance to
// die during that.
nsSVGAnimatedTransformList* mVal;
nsSVGElement* mElement;
};
};
} // namespace mozilla
#endif // MOZILLA_SVGANIMATEDTRANSFORMLIST_H__

View File

@ -24,7 +24,6 @@
#include "nsCSSProps.h"
#include "nsCSSParser.h"
#include "nsEventListenerManager.h"
#include "nsSVGAnimatedTransformList.h"
#include "nsSVGLength2.h"
#include "nsSVGNumber2.h"
#include "nsSVGNumberPair.h"
@ -39,6 +38,7 @@
#include "SVGAnimatedLengthList.h"
#include "SVGAnimatedPointList.h"
#include "SVGAnimatedPathSegList.h"
#include "SVGAnimatedTransformList.h"
#include "SVGContentUtils.h"
#include "nsIFrame.h"
#include <stdarg.h>
@ -589,8 +589,8 @@ nsSVGElement::ParseAttribute(int32_t aNamespaceID,
// Check for SVGAnimatedTransformList attribute
} else if (GetTransformListAttrName() == aAttribute) {
// The transform attribute is being set, so we must ensure that the
// nsSVGAnimatedTransformList is/has been allocated:
nsSVGAnimatedTransformList *transformList =
// SVGAnimatedTransformList is/has been allocated:
SVGAnimatedTransformList *transformList =
GetAnimatedTransformList(DO_ALLOCATE);
rv = transformList->SetBaseValueString(aValue);
if (NS_FAILED(rv)) {
@ -808,7 +808,7 @@ nsSVGElement::UnsetAttrInternal(int32_t aNamespaceID, nsIAtom* aName,
// Check if this is a transform list attribute going away
if (GetTransformListAttrName() == aName) {
nsSVGAnimatedTransformList *transformList = GetAnimatedTransformList();
SVGAnimatedTransformList *transformList = GetAnimatedTransformList();
if (transformList) {
MaybeSerializeAttrBeforeRemoval(aName, aNotify);
transformList->ClearBaseValue();

View File

@ -52,7 +52,7 @@ class SVGUserUnitList;
class SVGAnimatedPointList;
class SVGAnimatedPathSegList;
class SVGAnimatedPreserveAspectRatio;
class nsSVGAnimatedTransformList;
class SVGAnimatedTransformList;
class SVGStringList;
class DOMSVGStringList;
}
@ -77,7 +77,7 @@ public:
typedef mozilla::SVGAnimatedPointList SVGAnimatedPointList;
typedef mozilla::SVGAnimatedPathSegList SVGAnimatedPathSegList;
typedef mozilla::SVGAnimatedPreserveAspectRatio SVGAnimatedPreserveAspectRatio;
typedef mozilla::nsSVGAnimatedTransformList nsSVGAnimatedTransformList;
typedef mozilla::SVGAnimatedTransformList SVGAnimatedTransformList;
typedef mozilla::SVGStringList SVGStringList;
// nsISupports
@ -262,18 +262,18 @@ public:
return nullptr;
}
/**
* Get the nsSVGAnimatedTransformList for this element.
* Get the SVGAnimatedTransformList for this element.
*
* Despite the fact that animated transform lists are used for a variety of
* attributes, no SVG element uses more than one.
*
* It's relatively uncommon for elements to have their transform attribute
* set, so to save memory the nsSVGAnimatedTransformList is not allocated until
* set, so to save memory the SVGAnimatedTransformList is not allocated until
* the attribute is set/animated or its DOM wrapper is created. Callers that
* require the nsSVGAnimatedTransformList to be allocated and for this method
* require the SVGAnimatedTransformList to be allocated and for this method
* to return non-null must pass the DO_ALLOCATE flag.
*/
virtual nsSVGAnimatedTransformList* GetAnimatedTransformList(
virtual SVGAnimatedTransformList* GetAnimatedTransformList(
uint32_t aFlags = 0) {
return nullptr;
}

View File

@ -667,7 +667,8 @@ DOMInterfaces = {
},
'SVGAnimatedTransformList': {
'nativeOwnership': 'refcounted',
'nativeType': 'mozilla::DOMSVGAnimatedTransformList',
'headerFile': 'DOMSVGAnimatedTransformList.h'
},
'SVGAnimationElement': {

View File

@ -14,7 +14,7 @@
#include "nsContentUtils.h"
#include "nsIDOMSVGAnimatedNumber.h"
#include "nsSVGEffects.h"
#include "nsSVGAnimatedTransformList.h"
#include "SVGAnimatedTransformList.h"
// XXX Tight coupling with content classes ahead!
@ -157,10 +157,10 @@ nsSVGGradientFrame::GetSpreadMethod()
return GetEnumValue(dom::SVGGradientElement::SPREADMETHOD);
}
const nsSVGAnimatedTransformList*
const SVGAnimatedTransformList*
nsSVGGradientFrame::GetGradientTransformList(nsIContent* aDefault)
{
nsSVGAnimatedTransformList *thisTransformList =
SVGAnimatedTransformList *thisTransformList =
static_cast<dom::SVGGradientElement*>(mContent)->GetAnimatedTransformList();
if (thisTransformList && thisTransformList->IsExplicitlySet())
@ -201,7 +201,7 @@ nsSVGGradientFrame::GetGradientTransform(nsIFrame *aSource,
gfxMatrix(bbox.Width(), 0, 0, bbox.Height(), bbox.X(), bbox.Y());
}
const nsSVGAnimatedTransformList* animTransformList =
const SVGAnimatedTransformList* animTransformList =
GetGradientTransformList(mContent);
if (!animTransformList)
return bboxMatrix;

View File

@ -22,7 +22,7 @@ class nsStyleContext;
struct gfxRect;
namespace mozilla {
class nsSVGAnimatedTransformList;
class SVGAnimatedTransformList;
namespace dom {
class SVGLinearGradientElement;
@ -79,7 +79,7 @@ private:
void GetStopInformation(int32_t aIndex,
float *aOffset, nscolor *aColor, float *aStopOpacity);
const mozilla::nsSVGAnimatedTransformList* GetGradientTransformList(
const mozilla::SVGAnimatedTransformList* GetGradientTransformList(
nsIContent* aDefault);
// Will be singular for gradientUnits="objectBoundingBox" with an empty bbox.
gfxMatrix GetGradientTransform(nsIFrame *aSource,

View File

@ -20,7 +20,7 @@
#include "nsSVGGeometryFrame.h"
#include "mozilla/dom/SVGPatternElement.h"
#include "nsSVGUtils.h"
#include "nsSVGAnimatedTransformList.h"
#include "SVGAnimatedTransformList.h"
#include "SVGContentUtils.h"
using namespace mozilla;
@ -443,10 +443,10 @@ nsSVGPatternFrame::GetEnumValue(uint32_t aIndex, nsIContent *aDefault)
mEnumAttributes[aIndex].GetAnimValue();
}
nsSVGAnimatedTransformList*
SVGAnimatedTransformList*
nsSVGPatternFrame::GetPatternTransformList(nsIContent* aDefault)
{
nsSVGAnimatedTransformList *thisTransformList =
SVGAnimatedTransformList *thisTransformList =
static_cast<SVGPatternElement *>(mContent)->GetAnimatedTransformList();
if (thisTransformList && thisTransformList->IsExplicitlySet())
@ -462,7 +462,7 @@ nsSVGPatternFrame::GetPatternTransformList(nsIContent* aDefault)
gfxMatrix
nsSVGPatternFrame::GetPatternTransform()
{
nsSVGAnimatedTransformList* animTransformList =
SVGAnimatedTransformList* animTransformList =
GetPatternTransformList(mContent);
if (!animTransformList)
return gfxMatrix();

View File

@ -18,7 +18,7 @@ class nsSVGViewBox;
namespace mozilla {
class SVGAnimatedPreserveAspectRatio;
class nsSVGAnimatedTransformList;
class SVGAnimatedTransformList;
} // namespace mozilla
typedef nsSVGPaintServerFrame nsSVGPatternFrameBase;
@ -90,7 +90,7 @@ protected:
{
return GetEnumValue(aIndex, mContent);
}
mozilla::nsSVGAnimatedTransformList* GetPatternTransformList(
mozilla::SVGAnimatedTransformList* GetPatternTransformList(
nsIContent* aDefault);
gfxMatrix GetPatternTransform();
const nsSVGViewBox &GetViewBox(nsIContent *aDefault);