From bdc7e4ee3e204f55a084c7b554a35d4f7dde6f73 Mon Sep 17 00:00:00 2001 From: Brian Birtles Date: Sun, 25 Sep 2011 22:04:31 +0100 Subject: [PATCH] Bug 602759 part 7 - Refactor nsSVGAnimatedTransformList into SVGAnimatedTransformList and DOMSVGAnimatedTransformList and incorporate nsSVGTransformSMILAttr; r=jwatt --HG-- rename : content/svg/content/src/nsSVGAnimatedTransformList.cpp => content/svg/content/src/DOMSVGAnimatedTransformList.cpp rename : content/svg/content/src/nsSVGAnimatedTransformList.h => content/svg/content/src/DOMSVGAnimatedTransformList.h --- .../src/DOMSVGAnimatedTransformList.cpp | 176 +++++++ .../content/src/DOMSVGAnimatedTransformList.h | 155 ++++++ content/svg/content/src/Makefile.in | 4 +- .../content/src/SVGAnimatedTransformList.cpp | 355 ++++++++++++++ .../content/src/SVGAnimatedTransformList.h | 158 +++++++ .../src/nsSVGAnimateTransformElement.cpp | 1 - .../src/nsSVGAnimatedTransformList.cpp | 184 ------- .../content/src/nsSVGAnimatedTransformList.h | 97 ---- .../content/src/nsSVGTransformSMILAttr.cpp | 447 ------------------ .../svg/content/src/nsSVGTransformSMILAttr.h | 90 ---- 10 files changed, 846 insertions(+), 821 deletions(-) create mode 100644 content/svg/content/src/DOMSVGAnimatedTransformList.cpp create mode 100644 content/svg/content/src/DOMSVGAnimatedTransformList.h create mode 100644 content/svg/content/src/SVGAnimatedTransformList.cpp create mode 100644 content/svg/content/src/SVGAnimatedTransformList.h delete mode 100644 content/svg/content/src/nsSVGAnimatedTransformList.cpp delete mode 100644 content/svg/content/src/nsSVGAnimatedTransformList.h delete mode 100644 content/svg/content/src/nsSVGTransformSMILAttr.cpp delete mode 100644 content/svg/content/src/nsSVGTransformSMILAttr.h diff --git a/content/svg/content/src/DOMSVGAnimatedTransformList.cpp b/content/svg/content/src/DOMSVGAnimatedTransformList.cpp new file mode 100644 index 000000000000..4966d3c2fd33 --- /dev/null +++ b/content/svg/content/src/DOMSVGAnimatedTransformList.cpp @@ -0,0 +1,176 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Mozilla SVG project. + * + * The Initial Developer of the Original Code is + * Crocodile Clips Ltd.. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alex Fritze (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "DOMSVGAnimatedTransformList.h" +#include "DOMSVGTransformList.h" +#include "SVGAnimatedTransformList.h" +#include "nsSVGAttrTearoffTable.h" + +namespace mozilla { + +static + nsSVGAttrTearoffTable + sSVGAnimatedTransformListTearoffTable; + +NS_SVG_VAL_IMPL_CYCLE_COLLECTION(DOMSVGAnimatedTransformList, mElement) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGAnimatedTransformList) +NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGAnimatedTransformList) + +} // namespace mozilla +DOMCI_DATA(SVGAnimatedTransformList, mozilla::DOMSVGAnimatedTransformList) +namespace mozilla { + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGAnimatedTransformList) + NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimatedTransformList) + NS_INTERFACE_MAP_ENTRY(nsISupports) + NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGAnimatedTransformList) +NS_INTERFACE_MAP_END + +//---------------------------------------------------------------------- +// nsIDOMSVGAnimatedTransformList methods: + +/* readonly attribute nsIDOMSVGTransformList baseVal; */ +NS_IMETHODIMP +DOMSVGAnimatedTransformList::GetBaseVal(nsIDOMSVGTransformList** aBaseVal) +{ + if (!mBaseVal) { + mBaseVal = new DOMSVGTransformList(this, InternalAList().GetBaseValue()); + } + NS_ADDREF(*aBaseVal = mBaseVal); + return NS_OK; +} + +/* readonly attribute nsIDOMSVGTransformList animVal; */ +NS_IMETHODIMP +DOMSVGAnimatedTransformList::GetAnimVal(nsIDOMSVGTransformList** aAnimVal) +{ + if (!mAnimVal) { + mAnimVal = new DOMSVGTransformList(this, InternalAList().GetAnimValue()); + } + NS_ADDREF(*aAnimVal = mAnimVal); + return NS_OK; +} + +/* static */ already_AddRefed +DOMSVGAnimatedTransformList::GetDOMWrapper(SVGAnimatedTransformList *aList, + nsSVGElement *aElement) +{ + DOMSVGAnimatedTransformList *wrapper = + sSVGAnimatedTransformListTearoffTable.GetTearoff(aList); + if (!wrapper) { + wrapper = new DOMSVGAnimatedTransformList(aElement); + sSVGAnimatedTransformListTearoffTable.AddTearoff(aList, wrapper); + } + NS_ADDREF(wrapper); + return wrapper; +} + +/* 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( + PRUint32 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 kungFuDeathGrip; + if (mBaseVal) { + if (aNewLength < mBaseVal->Length()) { + // 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( + PRUint32 aNewLength) +{ + if (mAnimVal) { + mAnimVal->InternalListLengthWillChange(aNewLength); + } +} + +PRBool +DOMSVGAnimatedTransformList::IsAnimating() const +{ + return InternalAList().IsAnimating(); +} + +SVGAnimatedTransformList& +DOMSVGAnimatedTransformList::InternalAList() +{ + return *mElement->GetAnimatedTransformList(); +} + +const SVGAnimatedTransformList& +DOMSVGAnimatedTransformList::InternalAList() const +{ + return *mElement->GetAnimatedTransformList(); +} + +} // namespace mozilla diff --git a/content/svg/content/src/DOMSVGAnimatedTransformList.h b/content/svg/content/src/DOMSVGAnimatedTransformList.h new file mode 100644 index 000000000000..51ab37804e0f --- /dev/null +++ b/content/svg/content/src/DOMSVGAnimatedTransformList.h @@ -0,0 +1,155 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Mozilla SVG project. + * + * The Initial Developer of the Original Code is + * Crocodile Clips Ltd.. + * Portions created by the Initial Developer are Copyright (C) 2001 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Alex Fritze (original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either of the GNU General Public License Version 2 or later (the "GPL"), + * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MOZILLA_DOMSVGANIMATEDTRANSFORMLIST_H__ +#define MOZILLA_DOMSVGANIMATEDTRANSFORMLIST_H__ + +#include "nsIDOMSVGAnimTransformList.h" +#include "nsCycleCollectionParticipant.h" +#include "nsAutoPtr.h" +#include "nsTArray.h" + +class nsSVGElement; + +namespace mozilla { + +class SVGAnimatedTransformList; +class SVGTransformList; +class DOMSVGTransformList; + +/** + * 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 : public nsIDOMSVGAnimatedTransformList +{ + friend class DOMSVGTransformList; + +public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS(DOMSVGAnimatedTransformList) + NS_DECL_NSIDOMSVGANIMATEDTRANSFORMLIST + + /** + * 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 + 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 nsnull 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(PRUint32 aNewLength); + void InternalAnimValListWillChangeLengthTo(PRUint32 aNewLength); + + /** + * Returns true if our attribute is animating (in which case our animVal is + * not simply a mirror of our baseVal). + */ + PRBool IsAnimating() const; + +private: + + /** + * Only our static GetDOMWrapper() factory method may create objects of our + * type. + */ + DOMSVGAnimatedTransformList(nsSVGElement *aElement) + : mBaseVal(nsnull) + , mAnimVal(nsnull) + , mElement(aElement) + {} + + ~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 mElement; +}; + +} // namespace mozilla + +#endif // MOZILLA_DOMSVGANIMATEDTRANSFORMLIST_H__ diff --git a/content/svg/content/src/Makefile.in b/content/svg/content/src/Makefile.in index 931c0ec20558..a297529a6ee9 100644 --- a/content/svg/content/src/Makefile.in +++ b/content/svg/content/src/Makefile.in @@ -51,6 +51,7 @@ LIBXUL_LIBRARY = 1 CPPSRCS = \ DOMSVGAnimatedLengthList.cpp \ DOMSVGAnimatedNumberList.cpp \ + DOMSVGAnimatedTransformList.cpp \ DOMSVGLength.cpp \ DOMSVGLengthList.cpp \ DOMSVGMatrix.cpp \ @@ -67,7 +68,6 @@ CPPSRCS = \ nsSVGAElement.cpp \ nsSVGAltGlyphElement.cpp \ nsSVGAngle.cpp \ - nsSVGAnimatedTransformList.cpp \ nsSVGBoolean.cpp \ nsSVGCircleElement.cpp \ nsSVGClass.cpp \ @@ -129,6 +129,7 @@ CPPSRCS = \ SVGAnimatedPathSegList.cpp \ SVGAnimatedPointList.cpp \ SVGAnimatedPreserveAspectRatio.cpp \ + SVGAnimatedTransformList.cpp \ SVGLength.cpp \ SVGLengthList.cpp \ SVGNumberList.cpp \ @@ -147,7 +148,6 @@ CPPSRCS += nsSVGAnimateElement.cpp \ nsSVGMpathElement.cpp \ nsSVGSetElement.cpp \ nsSVGTransformSMILType.cpp \ - nsSVGTransformSMILAttr.cpp \ SVGIntegerPairSMILType.cpp \ SVGLengthListSMILType.cpp \ SVGMotionSMILType.cpp \ diff --git a/content/svg/content/src/SVGAnimatedTransformList.cpp b/content/svg/content/src/SVGAnimatedTransformList.cpp new file mode 100644 index 000000000000..0d7b17102869 --- /dev/null +++ b/content/svg/content/src/SVGAnimatedTransformList.cpp @@ -0,0 +1,355 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SVG Project code. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "SVGAnimatedTransformList.h" +#include "DOMSVGAnimatedTransformList.h" + +#ifdef MOZ_SMIL +#include "nsSMILValue.h" +#include "SVGTransform.h" +#include "SVGTransformListSMILType.h" +#include "nsSVGUtils.h" +#include "prdtoa.h" +#endif // MOZ_SMIL + +namespace mozilla { + +nsresult +SVGAnimatedTransformList::SetBaseValueString(const nsAString& aValue) +{ + SVGTransformList newBaseValue; + nsresult rv = newBaseValue.SetValueFromString(aValue); + if (NS_FAILED(rv)) { + return rv; + } + + 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 nsGenericElement::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 = PR_TRUE; + } + return rv; +} + +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 = PR_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 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 +SVGAnimatedTransformList::ClearAnimValue(nsSVGElement *aElement) +{ + 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 = nsnull; + aElement->DidAnimateTransformList(); +} + +PRBool +SVGAnimatedTransformList::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 PR_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; +} + +#ifdef MOZ_SMIL +nsISMILAttr* +SVGAnimatedTransformList::ToSMILAttr(nsSVGElement* aSVGElement) +{ + return new SMILAnimatedTransformList(this, aSVGElement); +} + +nsresult +SVGAnimatedTransformList::SMILAnimatedTransformList::ValueFromString( + const nsAString& aStr, + const nsISMILAnimationElement* aSrcElement, + nsSMILValue& aValue, + PRBool& 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 = PR_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 }; + PRInt32 numParsed = ParseParameterList(aSpec, params, 3); + PRUint16 transformType; + + if (aTransformType == nsGkAtoms::translate) { + // tx [ty=0] + if (numParsed != 1 && numParsed != 2) + return; + transformType = nsIDOMSVGTransform::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 = nsIDOMSVGTransform::SVG_TRANSFORM_SCALE; + } else if (aTransformType == nsGkAtoms::rotate) { + // r [cx=0 cy=0] + if (numParsed != 1 && numParsed != 3) + return; + transformType = nsIDOMSVGTransform::SVG_TRANSFORM_ROTATE; + } else if (aTransformType == nsGkAtoms::skewX) { + // x-angle + if (numParsed != 1) + return; + transformType = nsIDOMSVGTransform::SVG_TRANSFORM_SKEWX; + } else if (aTransformType == nsGkAtoms::skewY) { + // y-angle + if (numParsed != 1) + return; + transformType = nsIDOMSVGTransform::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 + +PRInt32 +SVGAnimatedTransformList::SMILAnimatedTransformList::ParseParameterList( + const nsAString& aSpec, + float* aVars, + PRInt32 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); + } +} + +#endif // MOZ_SMIL + +} // namespace mozilla diff --git a/content/svg/content/src/SVGAnimatedTransformList.h b/content/svg/content/src/SVGAnimatedTransformList.h new file mode 100644 index 000000000000..05111e2f8606 --- /dev/null +++ b/content/svg/content/src/SVGAnimatedTransformList.h @@ -0,0 +1,158 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla SVG Project code. + * + * The Initial Developer of the Original Code is the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brian Birtles + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef MOZILLA_SVGANIMATEDTRANSFORMLIST_H__ +#define MOZILLA_SVGANIMATEDTRANSFORMLIST_H__ + +#include "SVGTransformList.h" + +class nsSVGElement; + +#ifdef MOZ_SMIL +#include "nsISMILAttr.h" +#endif // MOZ_SMIL + +namespace mozilla { + +/** + * Class SVGAnimatedTransformList + * + * 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. + * + * 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 +{ + // friends so that they can get write access to mBaseVal + friend class DOMSVGTransform; + friend class DOMSVGTransformList; + +public: + SVGAnimatedTransformList() : mIsAttrSet(PR_FALSE) { } + + /** + * 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. + */ + 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); + + PRBool IsExplicitlySet() const; + + PRBool IsAnimating() const { + return !!mAnimVal; + } + +#ifdef MOZ_SMIL + /// Callers own the returned nsISMILAttr + nsISMILAttr* ToSMILAttr(nsSVGElement* aSVGElement); +#endif // MOZ_SMIL + +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 (). + + SVGTransformList mBaseVal; + nsAutoPtr mAnimVal; + PRPackedBool mIsAttrSet; + +#ifdef MOZ_SMIL + struct SMILAnimatedTransformList : public nsISMILAttr + { + public: + SMILAnimatedTransformList(SVGAnimatedTransformList* aVal, + nsSVGElement* aSVGElement) + : mVal(aVal) + , mElement(aSVGElement) + {} + + // nsISMILAttr methods + virtual nsresult ValueFromString(const nsAString& aStr, + const nsISMILAnimationElement* aSrcElement, + nsSMILValue& aValue, + PRBool& 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 PRInt32 ParseParameterList(const nsAString& aSpec, float* aVars, + PRInt32 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. + SVGAnimatedTransformList* mVal; + nsSVGElement* mElement; + }; +#endif // MOZ_SMIL +}; + +} // namespace mozilla + +#endif // MOZILLA_SVGANIMATEDTRANSFORMLIST_H__ diff --git a/content/svg/content/src/nsSVGAnimateTransformElement.cpp b/content/svg/content/src/nsSVGAnimateTransformElement.cpp index 1468b739f52b..df8b3fad3920 100644 --- a/content/svg/content/src/nsSVGAnimateTransformElement.cpp +++ b/content/svg/content/src/nsSVGAnimateTransformElement.cpp @@ -42,7 +42,6 @@ #include "nsSVGEnum.h" #include "nsIDOMSVGTransform.h" #include "nsIDOMSVGTransformable.h" -#include "nsSVGAnimatedTransformList.h" #include "nsSVGTransformSMILAttr.h" #include "nsSMILAnimationFunction.h" diff --git a/content/svg/content/src/nsSVGAnimatedTransformList.cpp b/content/svg/content/src/nsSVGAnimatedTransformList.cpp deleted file mode 100644 index 17976ca23190..000000000000 --- a/content/svg/content/src/nsSVGAnimatedTransformList.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Mozilla SVG project. - * - * The Initial Developer of the Original Code is - * Crocodile Clips Ltd.. - * Portions created by the Initial Developer are Copyright (C) 2001 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Alex Fritze (original author) - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "nsSVGAnimatedTransformList.h" -#include "nsSVGTransformList.h" -#include "nsContentUtils.h" - -//---------------------------------------------------------------------- -// Implementation - -nsSVGAnimatedTransformList::~nsSVGAnimatedTransformList() -{ - if (!mBaseVal) return; - nsCOMPtr val = do_QueryInterface(mBaseVal); - if (!val) return; - val->RemoveObserver(this); -} - -void -nsSVGAnimatedTransformList::Init(nsIDOMSVGTransformList* baseVal) -{ - mBaseVal = baseVal; - if (!mBaseVal) return; - nsCOMPtr val = do_QueryInterface(mBaseVal); - if (!val) return; - val->AddObserver(this); -} - -//---------------------------------------------------------------------- -// nsISupports methods: - -NS_IMPL_ADDREF(nsSVGAnimatedTransformList) -NS_IMPL_RELEASE(nsSVGAnimatedTransformList) - -DOMCI_DATA(SVGAnimatedTransformList, nsSVGAnimatedTransformList) - -NS_INTERFACE_MAP_BEGIN(nsSVGAnimatedTransformList) - NS_INTERFACE_MAP_ENTRY(nsISVGValue) - NS_INTERFACE_MAP_ENTRY(nsIDOMSVGAnimatedTransformList) - NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) - NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver) - NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGAnimatedTransformList) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISVGValue) -NS_INTERFACE_MAP_END - - -//---------------------------------------------------------------------- -// nsISVGValue methods: - -NS_IMETHODIMP -nsSVGAnimatedTransformList::SetValueString(const nsAString& aValue) -{ - nsCOMPtr value = do_QueryInterface(mBaseVal); - return value->SetValueString(aValue); -} - -NS_IMETHODIMP -nsSVGAnimatedTransformList::GetValueString(nsAString& aValue) -{ - nsCOMPtr value = do_QueryInterface(mBaseVal); - return value->GetValueString(aValue); -} - -//---------------------------------------------------------------------- -// nsIDOMSVGAnimatedTransformList methods: - -/* readonly attribute nsIDOMSVGTransformList baseVal; */ -NS_IMETHODIMP -nsSVGAnimatedTransformList::GetBaseVal(nsIDOMSVGTransformList** aBaseVal) -{ - *aBaseVal = mBaseVal; - NS_ADDREF(*aBaseVal); - return NS_OK; -} - -/* readonly attribute nsIDOMSVGTransformList animVal; */ -NS_IMETHODIMP -nsSVGAnimatedTransformList::GetAnimVal(nsIDOMSVGTransformList** aAnimVal) -{ - *aAnimVal = mAnimVal ? mAnimVal : mBaseVal; - NS_ADDREF(*aAnimVal); - return NS_OK; -} - -//---------------------------------------------------------------------- -// nsISVGValueObserver methods - -NS_IMETHODIMP -nsSVGAnimatedTransformList::WillModifySVGObservable(nsISVGValue* observable, - modificationType aModType) -{ - WillModify(aModType); - return NS_OK; -} - -NS_IMETHODIMP -nsSVGAnimatedTransformList::DidModifySVGObservable (nsISVGValue* observable, - modificationType aModType) -{ - DidModify(aModType); - return NS_OK; -} - -//---------------------------------------------------------------------- -// Misc nsSVGAnimatedTransformList methods - -PRBool -nsSVGAnimatedTransformList::IsExplicitlySet() const -{ - // XXX Dummy implementation until bug 602759 is fixed. - // Like other methods of this name, we need to know when a transform value has - // been explicitly set (either by markup, a DOM call, or animation). - // Given our current implementation, we can say that's the case so long as - // mBaseVal has something in it or mAnimVal exists. - // It's not quite right because, for example, if we have transform="" we - // should probably behave as if the value is set, but for now it will do until - // bug 602759 is fixed. - if (mAnimVal) - return PR_TRUE; - - if (!mBaseVal) - return PR_FALSE; - - PRUint32 numItems = 0; - nsIDOMSVGTransformList *list = mBaseVal.get(); - list->GetNumberOfItems(&numItems); - return numItems > 0; -} - -//////////////////////////////////////////////////////////////////////// -// Exported creation functions: - -nsresult -NS_NewSVGAnimatedTransformList(nsIDOMSVGAnimatedTransformList** result, - nsIDOMSVGTransformList* baseVal) -{ - *result = nsnull; - - nsSVGAnimatedTransformList* animatedTransformList = new nsSVGAnimatedTransformList(); - if(!animatedTransformList) return NS_ERROR_OUT_OF_MEMORY; - NS_ADDREF(animatedTransformList); - - animatedTransformList->Init(baseVal); - - *result = (nsIDOMSVGAnimatedTransformList*) animatedTransformList; - - return NS_OK; -} - diff --git a/content/svg/content/src/nsSVGAnimatedTransformList.h b/content/svg/content/src/nsSVGAnimatedTransformList.h deleted file mode 100644 index 94ab20e97db1..000000000000 --- a/content/svg/content/src/nsSVGAnimatedTransformList.h +++ /dev/null @@ -1,97 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Mozilla SVG project. - * - * The Initial Developer of the Original Code is - * Crocodile Clips Ltd.. - * Portions created by the Initial Developer are Copyright (C) 2001 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Alex Fritze (original author) - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef __NS_SVGANIMATEDTRANSFORMLIST_H__ -#define __NS_SVGANIMATEDTRANSFORMLIST_H__ - -#include "nsIDOMSVGAnimTransformList.h" -#include "nsIDOMSVGTransformList.h" -#include "nsSVGValue.h" - -//////////////////////////////////////////////////////////////////////// -// nsSVGAnimatedTransformList - -class nsSVGTransformSMILAttr; - -class nsSVGAnimatedTransformList : public nsIDOMSVGAnimatedTransformList, - public nsSVGValue, - public nsISVGValueObserver -{ -protected: - friend nsresult - NS_NewSVGAnimatedTransformList(nsIDOMSVGAnimatedTransformList** result, - nsIDOMSVGTransformList* baseVal); - - ~nsSVGAnimatedTransformList(); - void Init(nsIDOMSVGTransformList* baseVal); - -public: - // nsISupports interface: - NS_DECL_ISUPPORTS - - // nsIDOMSVGAnimatedTransformList interface: - NS_DECL_NSIDOMSVGANIMATEDTRANSFORMLIST - - // remainder of nsISVGValue interface: - NS_IMETHOD SetValueString(const nsAString& aValue); - NS_IMETHOD GetValueString(nsAString& aValue); - - // nsISVGValueObserver - NS_IMETHOD WillModifySVGObservable(nsISVGValue* observable, - modificationType aModType); - NS_IMETHOD DidModifySVGObservable (nsISVGValue* observable, - modificationType aModType); - - // nsISupportsWeakReference - // implementation inherited from nsSupportsWeakReference - - PRBool IsExplicitlySet() const; - -protected: - friend class nsSVGTransformSMILAttr; - - nsCOMPtr mBaseVal; - // XXX This should be read-only, i.e. its setters should throw - nsCOMPtr mAnimVal; -}; - -nsresult -NS_NewSVGAnimatedTransformList(nsIDOMSVGAnimatedTransformList** result, - nsIDOMSVGTransformList* baseVal); - -#endif //__NS_SVGANIMATEDTRANSFORMLIST_H__ diff --git a/content/svg/content/src/nsSVGTransformSMILAttr.cpp b/content/svg/content/src/nsSVGTransformSMILAttr.cpp deleted file mode 100644 index 244860dbb697..000000000000 --- a/content/svg/content/src/nsSVGTransformSMILAttr.cpp +++ /dev/null @@ -1,447 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Mozilla SVG project. - * - * The Initial Developer of the Original Code is Brian Birtles. - * Portions created by the Initial Developer are Copyright (C) 2006 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Brian Birtles - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#include "nsSVGTransformSMILAttr.h" -#include "nsSVGTransformSMILType.h" -#include "nsSVGAnimatedTransformList.h" -#include "nsSVGTransformList.h" -#include "nsSVGTransform.h" -#include "nsIDOMSVGTransform.h" -#include "nsIDOMSVGMatrix.h" -#include "nsSVGMatrix.h" -#include "nsSMILValue.h" -#include "nsSMILNullType.h" -#include "nsISMILAnimationElement.h" -#include "nsSVGElement.h" -#include "nsISVGValue.h" -#include "prdtoa.h" -#include "prlog.h" -#include "nsMathUtils.h" - -nsresult -nsSVGTransformSMILAttr::ValueFromString(const nsAString& aStr, - const nsISMILAnimationElement* aSrcElement, - nsSMILValue& aValue, - PRBool& aPreventCachingOfSandwich) const -{ - NS_ENSURE_TRUE(aSrcElement, NS_ERROR_FAILURE); - NS_ASSERTION(aValue.IsNull(), - "aValue should have been cleared before calling ValueFromString"); - - const nsAttrValue* typeAttr = aSrcElement->GetAnimAttr(nsGkAtoms::type); - const nsIAtom* transformType = nsGkAtoms::translate; - 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 it means our |type| was invalid. - return NS_ERROR_FAILURE; - } - transformType = typeAttr->GetAtomValue(); - } - - ParseValue(aStr, transformType, aValue); - aPreventCachingOfSandwich = PR_FALSE; - return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK; -} - -nsSMILValue -nsSVGTransformSMILAttr::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(&nsSVGTransformSMILType::sSingleton); - - nsIDOMSVGTransformList *list = mVal->mBaseVal.get(); - - PRUint32 numItems = 0; - list->GetNumberOfItems(&numItems); - for (PRUint32 i = 0; i < numItems; i++) { - nsCOMPtr transform; - nsresult rv = list->GetItem(i, getter_AddRefs(transform)); - if (NS_SUCCEEDED(rv) && transform) { - rv = AppendSVGTransformToSMILValue(transform.get(), val); - if (NS_FAILED(rv)) { // Appending to |val| failed (OOM?) - val = nsSMILValue(); - break; - } - } - } - - return val; -} - -void -nsSVGTransformSMILAttr::ClearAnimValue() -{ - PRBool animValSet = !!mVal->mAnimVal; - mVal->mAnimVal = nsnull; - if (animValSet) { - mSVGElement->DidAnimateTransform(); - } -} - -nsresult -nsSVGTransformSMILAttr::SetAnimValue(const nsSMILValue& aValue) -{ - if (aValue.mType != &nsSVGTransformSMILType::sSingleton) { - NS_WARNING("Unexpected SMIL Type"); - return NS_ERROR_FAILURE; - } - - nsresult rv = NS_OK; - - // Create the anim value if necessary - if (!mVal->mAnimVal) { - rv = nsSVGTransformList::Create(getter_AddRefs(mVal->mAnimVal)); - NS_ENSURE_SUCCESS(rv,rv); - } - - // Do a minimal update on the anim value and if anything fails, set the anim - // value to null so that calls to nsSVGAnimatedTransformList::GetAnimVal will - // return the base value instead. - rv = UpdateFromSMILValue(mVal->mAnimVal, aValue); - if (NS_FAILED(rv)) { - mVal->mAnimVal = nsnull; - } - NS_ENSURE_SUCCESS(rv,rv); - - mSVGElement->DidAnimateTransform(); - return NS_OK; -} - -//---------------------------------------------------------------------- -// Implementation helpers - -void -nsSVGTransformSMILAttr::ParseValue(const nsAString& aSpec, - const nsIAtom* aTransformType, - nsSMILValue& aResult) -{ - NS_ASSERTION(aResult.IsNull(), "Unexpected type for SMIL value"); - - // nsSVGSMILTransform constructor should be expecting array with 3 params - PR_STATIC_ASSERT(nsSVGSMILTransform::NUM_SIMPLE_PARAMS == 3); - - float params[3] = { 0.f }; - PRInt32 numParsed = ParseParameterList(aSpec, params, 3); - nsSVGSMILTransform::TransformType transformType; - - if (aTransformType == nsGkAtoms::translate) { - // tx [ty=0] - if (numParsed != 1 && numParsed != 2) - return; - transformType = nsSVGSMILTransform::TRANSFORM_TRANSLATE; - } else if (aTransformType == nsGkAtoms::scale) { - // sx [sy=sx] - if (numParsed != 1 && numParsed != 2) - return; - if (numParsed == 1) { - params[1] = params[0]; - } - transformType = nsSVGSMILTransform::TRANSFORM_SCALE; - } else if (aTransformType == nsGkAtoms::rotate) { - // r [cx=0 cy=0] - if (numParsed != 1 && numParsed != 3) - return; - transformType = nsSVGSMILTransform::TRANSFORM_ROTATE; - } else if (aTransformType == nsGkAtoms::skewX) { - // x-angle - if (numParsed != 1) - return; - transformType = nsSVGSMILTransform::TRANSFORM_SKEWX; - } else if (aTransformType == nsGkAtoms::skewY) { - // y-angle - if (numParsed != 1) - return; - transformType = nsSVGSMILTransform::TRANSFORM_SKEWY; - } else { - return; - } - - nsSMILValue val(&nsSVGTransformSMILType::sSingleton); - nsSVGSMILTransform transform(transformType, params); - if (NS_FAILED(nsSVGTransformSMILType::AppendTransform(transform, val))) { - return; - } - - // Success! Populate our outparam with parsed value. - aResult.Swap(val); -} - -inline PRBool -IsSpace(const char c) -{ - return (c == 0x9 || c == 0xA || c == 0xD || c == 0x20); -} - -inline void -SkipWsp(nsACString::const_iterator& aIter, - const nsACString::const_iterator& aIterEnd) -{ - while (aIter != aIterEnd && IsSpace(*aIter)) - ++aIter; -} - -PRInt32 -nsSVGTransformSMILAttr::ParseParameterList(const nsAString& aSpec, - float* aVars, - PRInt32 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; -} - -nsresult -nsSVGTransformSMILAttr::AppendSVGTransformToSMILValue( - nsIDOMSVGTransform* aTransform, nsSMILValue& aValue) -{ - NS_ASSERTION(aValue.mType == &nsSVGTransformSMILType::sSingleton, - "Unexpected type for SMIL value"); - - PRUint16 svgTransformType = nsIDOMSVGTransform::SVG_TRANSFORM_MATRIX; - aTransform->GetType(&svgTransformType); - - nsCOMPtr matrix; - nsresult rv = aTransform->GetMatrix(getter_AddRefs(matrix)); - if (NS_FAILED(rv) || !matrix) - return NS_ERROR_FAILURE; - - // nsSVGSMILTransform constructor should be expecting array with 3 params - PR_STATIC_ASSERT(nsSVGSMILTransform::NUM_SIMPLE_PARAMS == 3); - float params[3] = { 0.f }; - nsSVGSMILTransform::TransformType transformType; - - switch (svgTransformType) - { - case nsIDOMSVGTransform::SVG_TRANSFORM_TRANSLATE: - { - matrix->GetE(¶ms[0]); - matrix->GetF(¶ms[1]); - transformType = nsSVGSMILTransform::TRANSFORM_TRANSLATE; - } - break; - - case nsIDOMSVGTransform::SVG_TRANSFORM_SCALE: - { - matrix->GetA(¶ms[0]); - matrix->GetD(¶ms[1]); - transformType = nsSVGSMILTransform::TRANSFORM_SCALE; - } - break; - - case nsIDOMSVGTransform::SVG_TRANSFORM_ROTATE: - { - /* - * Unfortunately the SVG 1.1 DOM API for transforms doesn't allow us to - * query the center of rotation so we do some dirty casting to make up - * for it. - */ - nsSVGTransform* svgTransform = static_cast(aTransform); - svgTransform->GetAngle(¶ms[0]); - svgTransform->GetRotationOrigin(params[1], params[2]); - transformType = nsSVGSMILTransform::TRANSFORM_ROTATE; - } - break; - - case nsIDOMSVGTransform::SVG_TRANSFORM_SKEWX: - { - aTransform->GetAngle(¶ms[0]); - transformType = nsSVGSMILTransform::TRANSFORM_SKEWX; - } - break; - - case nsIDOMSVGTransform::SVG_TRANSFORM_SKEWY: - { - aTransform->GetAngle(¶ms[0]); - transformType = nsSVGSMILTransform::TRANSFORM_SKEWY; - } - break; - - case nsIDOMSVGTransform::SVG_TRANSFORM_MATRIX: - { - // nsSVGSMILTransform constructor for TRANSFORM_MATRIX type should be - // expecting array with 6 params - PR_STATIC_ASSERT(nsSVGSMILTransform::NUM_STORED_PARAMS == 6); - float mx[6]; - matrix->GetA(&mx[0]); - matrix->GetB(&mx[1]); - matrix->GetC(&mx[2]); - matrix->GetD(&mx[3]); - matrix->GetE(&mx[4]); - matrix->GetF(&mx[5]); - return nsSVGTransformSMILType::AppendTransform(nsSVGSMILTransform(mx), - aValue); - } - - case nsIDOMSVGTransform::SVG_TRANSFORM_UNKNOWN: - // If it's 'unknown', it's probably not initialised, so just skip it. - return NS_OK; - - default: - NS_WARNING("Trying to convert unrecognised SVG transform type"); - return NS_ERROR_FAILURE; - } - - NS_ABORT_IF_FALSE(transformType != nsSVGSMILTransform::TRANSFORM_MATRIX, - "generalized matrix case should have returned above"); - - return nsSVGTransformSMILType:: - AppendTransform(nsSVGSMILTransform(transformType, params), aValue); -} - -nsresult -nsSVGTransformSMILAttr::UpdateFromSMILValue( - nsIDOMSVGTransformList* aTransformList, const nsSMILValue& aValue) -{ - PRUint32 svgLength = -1; - aTransformList->GetNumberOfItems(&svgLength); - - nsSVGTransformSMILType* type = &nsSVGTransformSMILType::sSingleton; - PRUint32 smilLength = type->GetNumTransforms(aValue); - - nsresult rv = NS_OK; - - for (PRUint32 i = 0; i < smilLength; i++) { - nsCOMPtr transform; - if (i < svgLength) { - // Get the transform to update - rv = aTransformList->GetItem(i, getter_AddRefs(transform)); - NS_ENSURE_SUCCESS(rv,rv); - } else { - // Append another transform to the list - nsresult rv = NS_NewSVGTransform(getter_AddRefs(transform)); - NS_ENSURE_SUCCESS(rv,rv); - - nsCOMPtr result; - rv = aTransformList->AppendItem(transform, getter_AddRefs(result)); - NS_ENSURE_SUCCESS(rv,rv); - } - // Set the value - const nsSVGSMILTransform* smilTransform = type->GetTransformAt(i, aValue); - rv = GetSVGTransformFromSMILValue(*smilTransform, transform); - NS_ENSURE_SUCCESS(rv,rv); - } - - // Trim excess elements - while (svgLength > smilLength) { - nsCOMPtr removed; - rv = aTransformList->RemoveItem(--svgLength, getter_AddRefs(removed)); - NS_ENSURE_SUCCESS(rv,rv); - } - - return NS_OK; -} - -nsresult -nsSVGTransformSMILAttr::GetSVGTransformFromSMILValue( - const nsSVGSMILTransform& aSMILTransform, - nsIDOMSVGTransform* aSVGTransform) -{ - switch (aSMILTransform.mTransformType) - { - case nsSVGSMILTransform::TRANSFORM_TRANSLATE: - return aSVGTransform->SetTranslate(aSMILTransform.mParams[0], - aSMILTransform.mParams[1]); - - case nsSVGSMILTransform::TRANSFORM_SCALE: - return aSVGTransform->SetScale(aSMILTransform.mParams[0], - aSMILTransform.mParams[1]); - - case nsSVGSMILTransform::TRANSFORM_ROTATE: - return aSVGTransform->SetRotate(aSMILTransform.mParams[0], - aSMILTransform.mParams[1], - aSMILTransform.mParams[2]); - - case nsSVGSMILTransform::TRANSFORM_SKEWX: - return aSVGTransform->SetSkewX(aSMILTransform.mParams[0]); - - case nsSVGSMILTransform::TRANSFORM_SKEWY: - return aSVGTransform->SetSkewY(aSMILTransform.mParams[0]); - - case nsSVGSMILTransform::TRANSFORM_MATRIX: - { - nsCOMPtr svgMatrix; - nsresult rv = - NS_NewSVGMatrix(getter_AddRefs(svgMatrix), - aSMILTransform.mParams[0], - aSMILTransform.mParams[1], - aSMILTransform.mParams[2], - aSMILTransform.mParams[3], - aSMILTransform.mParams[4], - aSMILTransform.mParams[5]); - NS_ENSURE_SUCCESS(rv, rv); - NS_ABORT_IF_FALSE(svgMatrix, - "NS_NewSVGMatrix succeeded, so it should have " - "given us a non-null result"); - return aSVGTransform->SetMatrix(svgMatrix); - } - default: - NS_WARNING("Unexpected transform type"); - return NS_ERROR_FAILURE; - } -} diff --git a/content/svg/content/src/nsSVGTransformSMILAttr.h b/content/svg/content/src/nsSVGTransformSMILAttr.h deleted file mode 100644 index feb1b53d8422..000000000000 --- a/content/svg/content/src/nsSVGTransformSMILAttr.h +++ /dev/null @@ -1,90 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Mozilla SVG project. - * - * The Initial Developer of the Original Code is Brian Birtles. - * Portions created by the Initial Developer are Copyright (C) 2006 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Brian Birtles - * - * Alternatively, the contents of this file may be used under the terms of - * either of the GNU General Public License Version 2 or later (the "GPL"), - * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef NS_SVGTRANSFORMSMILATTR_H_ -#define NS_SVGTRANSFORMSMILATTR_H_ - -#include "nsISMILAttr.h" -#include "nsIAtom.h" -#include "nsString.h" - -class nsSVGElement; -class nsSVGAnimatedTransformList; -class nsISMILType; -class nsIDOMSVGTransform; -class nsIDOMSVGTransformList; -class nsSVGSMILTransform; - -class nsSVGTransformSMILAttr : public nsISMILAttr -{ -public: - nsSVGTransformSMILAttr(nsSVGAnimatedTransformList* aTransform, - nsSVGElement* aSVGElement) - : mVal(aTransform), mSVGElement(aSVGElement) {} - - // nsISMILAttr methods - virtual nsresult ValueFromString(const nsAString& aStr, - const nsISMILAnimationElement* aSrcElement, - nsSMILValue& aValue, - PRBool& 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 PRInt32 ParseParameterList(const nsAString& aSpec, float* aVars, - PRInt32 aNVars); - static nsresult AppendSVGTransformToSMILValue(nsIDOMSVGTransform* transform, - nsSMILValue& aValue); - static nsresult UpdateFromSMILValue(nsIDOMSVGTransformList* aTransformList, - const nsSMILValue& aValue); - static nsresult GetSVGTransformFromSMILValue( - const nsSVGSMILTransform& aSMILTransform, - nsIDOMSVGTransform* aSVGTransform); - -private: - // Raw pointers are OK here because this nsSVGTransformSMILAttr is both - // created & destroyed during a SMIL sample-step, during which time the DOM - // isn't modified. - nsSVGAnimatedTransformList* mVal; - nsSVGElement* mSVGElement; -}; - -#endif // NS_SVGTRANSFORMSMILATTR_H_