Bug 468996. Implement SMIL animateTransform element. r+sr=roc

This commit is contained in:
Brian Birtles 2009-01-19 22:14:16 +13:00
parent 9973adc34e
commit 802428be09
37 changed files with 2528 additions and 96 deletions

View File

@ -67,6 +67,7 @@ class nsSMILValue;
// | | | | |
// | -- Assign? | X | X | X |
// | -- Add? | - | X? | X |
// | -- SandwichAdd? | - | -? | X |
// | -- ComputeDistance? | - | - | X? |
// | -- Interpolate? | - | X | X |
// +---------------------+---------------+-------------+------------------+
@ -144,6 +145,30 @@ public:
const nsSMILValue& aValueToAdd,
PRUint32 aCount) const = 0;
/**
* Adds aValueToAdd to the underlying value in the animation sandwich, aDest.
*
* For most types this operation is identical to a regular Add() but for some
* types (notably <animateTransform>) the operation differs. For
* <animateTransform> Add() corresponds to simply adding together the
* transform parameters and is used when calculating cumulative values or
* by-animation values. On the other hand SandwichAdd() is used when adding to
* the underlying value and requires matrix post-multiplication. (This
* distinction is most clearly indicated by the SVGT1.2 test suite. It is not
* obvious within the SMIL specifications.)
*
* @param aDest The value to add to.
* @param aValueToAdd The value to add.
* @return NS_OK on success, an error code on failure.
*
* @pre aValueToAdd.mType == aDest.mType == this
*/
virtual nsresult SandwichAdd(nsSMILValue& aDest,
const nsSMILValue& aValueToAdd) const
{
return Add(aDest, aValueToAdd, 1);
}
/**
* Calculates the 'distance' between two values. This is the distance used in
* paced interpolation.

View File

@ -292,8 +292,9 @@ nsSMILAnimationFunction::ComposeResult(const nsISMILAttr& aSMILAttr,
}
// If additive animation isn't required or isn't supported, set the value.
if (!IsAdditive() || NS_FAILED(aResult.Add(result)))
if (!IsAdditive() || NS_FAILED(aResult.SandwichAdd(result))) {
aResult = result;
}
}
PRInt8

View File

@ -88,18 +88,32 @@ nsSMILValue::Add(const nsSMILValue& aValueToAdd, PRUint32 aCount)
if (aValueToAdd.IsNull()) return NS_OK;
if (aValueToAdd.mType != mType) {
NS_WARNING("Trying to add incompatible types.");
NS_ERROR("Trying to add incompatible types.");
return NS_ERROR_FAILURE;
}
return mType->Add(*this, aValueToAdd, aCount);
}
nsresult
nsSMILValue::SandwichAdd(const nsSMILValue& aValueToAdd)
{
if (aValueToAdd.IsNull())
return NS_OK;
if (aValueToAdd.mType != mType) {
NS_ERROR("Trying to add incompatible types.");
return NS_ERROR_FAILURE;
}
return mType->SandwichAdd(*this, aValueToAdd);
}
nsresult
nsSMILValue::ComputeDistance(const nsSMILValue& aTo, double& aDistance) const
{
if (aTo.mType != mType) {
NS_WARNING("Trying to calculate distance between incompatible types.");
NS_ERROR("Trying to calculate distance between incompatible types.");
return NS_ERROR_FAILURE;
}
@ -112,7 +126,7 @@ nsSMILValue::Interpolate(const nsSMILValue& aEndVal,
nsSMILValue& aResult) const
{
if (aEndVal.mType != mType) {
NS_WARNING("Trying to interpolate between incompatible types.");
NS_ERROR("Trying to interpolate between incompatible types.");
return NS_ERROR_FAILURE;
}

View File

@ -62,6 +62,7 @@ public:
}
nsresult Add(const nsSMILValue& aValueToAdd, PRUint32 aCount = 1);
nsresult SandwichAdd(const nsSMILValue& aValueToAdd);
nsresult ComputeDistance(const nsSMILValue& aTo, double& aDistance) const;
nsresult Interpolate(const nsSMILValue& aEndVal,
double aUnitDistance,

View File

@ -140,8 +140,11 @@ CPPSRCS = \
ifdef MOZ_SMIL
CPPSRCS += nsSVGAnimateElement.cpp \
nsSVGAnimateTransformElement.cpp \
nsSVGAnimationElement.cpp \
nsSVGSetElement.cpp \
nsSVGTransformSMILType.cpp \
nsSVGTransformSMILAttr.cpp \
$(NULL)
endif

View File

@ -0,0 +1,146 @@
/* -*- 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) 2005
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brian Birtles <birtles@gmail.com>
* Chris Double <chris.double@double.co.nz>
* Daniel Holbert <dholbert@mozilla.com>
*
* 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 "nsSVGAnimationElement.h"
#include "nsIDOMSVGAnimateTransformElement.h"
#include "nsSVGEnum.h"
#include "nsIDOMSVGTransform.h"
#include "nsIDOMSVGTransformable.h"
#include "nsSVGAnimatedTransformList.h"
#include "nsSVGTransformSMILAttr.h"
#include "nsSMILAnimationFunction.h"
typedef nsSVGAnimationElement nsSVGAnimateTransformElementBase;
class nsSVGAnimateTransformElement : public nsSVGAnimateTransformElementBase,
public nsIDOMSVGAnimateTransformElement
{
protected:
friend nsresult NS_NewSVGAnimateTransformElement(nsIContent **aResult,
nsINodeInfo *aNodeInfo);
nsSVGAnimateTransformElement(nsINodeInfo* aNodeInfo);
nsSMILAnimationFunction mAnimationFunction;
public:
// interfaces:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_NSIDOMSVGANIMATETRANSFORMELEMENT
NS_FORWARD_NSIDOMNODE(nsSVGAnimateTransformElementBase::)
NS_FORWARD_NSIDOMELEMENT(nsSVGAnimateTransformElementBase::)
NS_FORWARD_NSIDOMSVGELEMENT(nsSVGAnimateTransformElementBase::)
NS_FORWARD_NSIDOMSVGANIMATIONELEMENT(nsSVGAnimateTransformElementBase::)
// nsIDOMNode specializations
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
// nsGenericElement specializations
PRBool ParseAttribute(PRInt32 aNamespaceID,
nsIAtom* aAttribute,
const nsAString& aValue,
nsAttrValue& aResult);
// nsISMILAnimationElement
virtual nsSMILAnimationFunction& AnimationFunction();
};
NS_IMPL_NS_NEW_SVG_ELEMENT(AnimateTransform)
//----------------------------------------------------------------------
// nsISupports methods
NS_IMPL_ADDREF_INHERITED(nsSVGAnimateTransformElement,nsSVGAnimateTransformElementBase)
NS_IMPL_RELEASE_INHERITED(nsSVGAnimateTransformElement,nsSVGAnimateTransformElementBase)
NS_INTERFACE_TABLE_HEAD(nsSVGAnimateTransformElement)
NS_NODE_INTERFACE_TABLE5(nsSVGAnimateTransformElement, nsIDOMNode,
nsIDOMElement, nsIDOMSVGElement,
nsIDOMSVGAnimationElement,
nsIDOMSVGAnimateTransformElement)
NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(SVGAnimateElement)
NS_INTERFACE_MAP_END_INHERITING(nsSVGAnimateTransformElementBase)
//----------------------------------------------------------------------
// Implementation
nsSVGAnimateTransformElement::nsSVGAnimateTransformElement(nsINodeInfo *aNodeInfo)
: nsSVGAnimateTransformElementBase(aNodeInfo)
{
}
PRBool
nsSVGAnimateTransformElement::ParseAttribute(PRInt32 aNamespaceID,
nsIAtom* aAttribute,
const nsAString& aValue,
nsAttrValue& aResult)
{
// 'type' is an <animateTransform>-specific attribute, and we'll handle it
// specially.
if (aNamespaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::type) {
aResult.ParseAtom(aValue);
nsIAtom* atom = aResult.GetAtomValue();
if (atom != nsGkAtoms::translate &&
atom != nsGkAtoms::scale &&
atom != nsGkAtoms::rotate &&
atom != nsGkAtoms::skewX &&
atom != nsGkAtoms::skewY) {
ReportAttributeParseFailure(GetOwnerDoc(), aAttribute, aValue);
}
return PR_TRUE;
}
return nsSVGAnimateTransformElementBase::ParseAttribute(aNamespaceID,
aAttribute, aValue,
aResult);
}
//----------------------------------------------------------------------
// nsIDOMNode methods
NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGAnimateTransformElement)
//----------------------------------------------------------------------
// nsISMILAnimationElement methods
nsSMILAnimationFunction&
nsSVGAnimateTransformElement::AnimationFunction()
{
return mAnimationFunction;
}

View File

@ -38,62 +38,15 @@
#include "nsSVGAnimatedTransformList.h"
#include "nsSVGTransformList.h"
#include "nsSVGValue.h"
#include "nsWeakReference.h"
#include "nsContentUtils.h"
////////////////////////////////////////////////////////////////////////
// nsSVGAnimatedTransformList
class nsSVGAnimatedTransformList : public nsIDOMSVGAnimatedTransformList,
public nsSVGValue,
public nsISVGValueObserver
{
protected:
friend nsresult
NS_NewSVGAnimatedTransformList(nsIDOMSVGAnimatedTransformList** result,
nsIDOMSVGTransformList* baseVal);
nsSVGAnimatedTransformList();
~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
protected:
nsCOMPtr<nsIDOMSVGTransformList> mBaseVal;
};
//----------------------------------------------------------------------
// Implementation
nsSVGAnimatedTransformList::nsSVGAnimatedTransformList()
{
}
nsSVGAnimatedTransformList::~nsSVGAnimatedTransformList()
{
if (!mBaseVal) return;
nsCOMPtr<nsISVGValue> val = do_QueryInterface(mBaseVal);
nsCOMPtr<nsISVGValue> val = do_QueryInterface(mBaseVal);
if (!val) return;
val->RemoveObserver(this);
}
@ -146,7 +99,7 @@ nsSVGAnimatedTransformList::GetValueString(nsAString& aValue)
/* readonly attribute nsIDOMSVGTransformList baseVal; */
NS_IMETHODIMP
nsSVGAnimatedTransformList::GetBaseVal(nsIDOMSVGTransformList * *aBaseVal)
nsSVGAnimatedTransformList::GetBaseVal(nsIDOMSVGTransformList** aBaseVal)
{
*aBaseVal = mBaseVal;
NS_ADDREF(*aBaseVal);
@ -155,9 +108,9 @@ nsSVGAnimatedTransformList::GetBaseVal(nsIDOMSVGTransformList * *aBaseVal)
/* readonly attribute nsIDOMSVGTransformList animVal; */
NS_IMETHODIMP
nsSVGAnimatedTransformList::GetAnimVal(nsIDOMSVGTransformList * *aAnimVal)
nsSVGAnimatedTransformList::GetAnimVal(nsIDOMSVGTransformList** aAnimVal)
{
*aAnimVal = mBaseVal;
*aAnimVal = mAnimVal ? mAnimVal : mBaseVal;
NS_ADDREF(*aAnimVal);
return NS_OK;
}

View File

@ -41,6 +41,52 @@
#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
protected:
friend class nsSVGTransformSMILAttr;
nsCOMPtr<nsIDOMSVGTransformList> mBaseVal;
// XXX This should be read-only, i.e. its setters should throw
nsCOMPtr<nsIDOMSVGTransformList> mAnimVal;
};
nsresult
NS_NewSVGAnimatedTransformList(nsIDOMSVGAnimatedTransformList** result,

View File

@ -91,6 +91,8 @@
#include "prdtoa.h"
#include <stdarg.h>
#ifdef MOZ_SMIL
#include "nsSVGTransformSMILAttr.h"
#include "nsSVGAnimatedTransformList.h"
#include "nsIDOMSVGTransformable.h"
#endif // MOZ_SMIL
@ -1650,6 +1652,22 @@ nsSVGElement::RecompileScriptEventListeners()
nsISMILAttr*
nsSVGElement::GetAnimatedAttr(const nsIAtom* aName)
{
// Transforms:
if (aName == nsGkAtoms::transform) {
nsCOMPtr<nsIDOMSVGTransformable> transformable(
do_QueryInterface(static_cast<nsIContent*>(this)));
if (!transformable)
return nsnull;
nsCOMPtr<nsIDOMSVGAnimatedTransformList> transformList;
nsresult rv = transformable->GetTransform(getter_AddRefs(transformList));
NS_ENSURE_SUCCESS(rv, nsnull);
nsSVGAnimatedTransformList* list
= static_cast<nsSVGAnimatedTransformList*>(transformList.get());
NS_ENSURE_TRUE(list, nsnull);
return new nsSVGTransformSMILAttr(list, this);
}
// Lengths:
LengthAttributesInfo info = GetLengthInfo();
for (PRUint32 i = 0; i < info.mLengthCount; i++) {

View File

@ -165,6 +165,8 @@ NS_NewSVGFEDisplacementMapElement(nsIContent **aResult, nsINodeInfo *aNodeInfo);
nsresult
NS_NewSVGAnimateElement(nsIContent **aResult, nsINodeInfo *aNodeInfo);
nsresult
NS_NewSVGAnimateTransformElement(nsIContent **aResult, nsINodeInfo *aNodeInfo);
nsresult
NS_NewSVGSetElement(nsIContent **aResult, nsINodeInfo *aNodeInfo);
#endif // MOZ_SMIL
@ -299,6 +301,8 @@ NS_NewSVGElement(nsIContent** aResult, nsINodeInfo *aNodeInfo,
#ifdef MOZ_SMIL
if (name == nsGkAtoms::animate)
return NS_NewSVGAnimateElement(aResult, aNodeInfo);
if (name == nsGkAtoms::animateTransform)
return NS_NewSVGAnimateTransformElement(aResult, aNodeInfo);
if (name == nsGkAtoms::set)
return NS_NewSVGSetElement(aResult, aNodeInfo);
#endif // MOZ_SMIL

View File

@ -0,0 +1,110 @@
/* -*- 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) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brian Birtles <birtles@gmail.com>
*
* 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_SVGSMILTRANSFORM_H_
#define NS_SVGSMILTRANSFORM_H_
////////////////////////////////////////////////////////////////////////
// nsSVGSMILTransform
//
// A pared-down representation of an SVG transform used in SMIL animation. We
// just store the most basic facts about the transform such that we can add the
// transform parameters together and later reconstruct a full SVG transform from
// this information.
//
// The meaning of the mParams array depends on the transform type as follows:
//
// Type | mParams[0], mParams[1], mParams[2], ...
// --------------------+-----------------------------------------
// TRANSFORM_TRANSLATE | tx, ty
// TRANSFORM_SCALE | sx, sy
// TRANSFORM_ROTATE | rotation-angle (in degrees), cx, cy
// TRANSFORM_SKEWX | skew-angle (in degrees)
// TRANSFORM_SKEWY | skew-angle (in degrees)
// TRANSFORM_MATRIX | a, b, c, d, e, f
//
// TRANSFORM_MATRIX is never generated by animation code (it is only produced
// when the user inserts one via the DOM) and often requires special handling
// when we do encounter it. Therefore many users of this class are only
// interested in the first three parameters and so we provide a special
// constructor for setting those parameters only.
class nsSVGSMILTransform
{
public:
enum TransformType
{
TRANSFORM_TRANSLATE,
TRANSFORM_SCALE,
TRANSFORM_ROTATE,
TRANSFORM_SKEWX,
TRANSFORM_SKEWY,
TRANSFORM_MATRIX
};
nsSVGSMILTransform(TransformType aType)
: mTransformType(aType)
{
for (int i = 0; i < 6; ++i) {
mParams[i] = 0;
}
}
nsSVGSMILTransform(TransformType aType, float (&aParams)[3])
: mTransformType(aType)
{
for (int i = 0; i < 3; ++i) {
mParams[i] = aParams[i];
}
for (int i = 3; i < 6; ++i) {
mParams[i] = 0;
}
}
nsSVGSMILTransform(float (&aParams)[6])
: mTransformType(TRANSFORM_MATRIX)
{
for (int i = 0; i < 6; ++i) {
mParams[i] = aParams[i];
}
}
TransformType mTransformType;
float mParams[6];
};
#endif // NS_SVGSMILTRANSFORM_H_

View File

@ -39,54 +39,13 @@
#include "nsSVGTransform.h"
#include "prdtoa.h"
#include "nsSVGMatrix.h"
#include "nsSVGValue.h"
#include "nsISVGValueUtils.h"
#include "nsISVGValueObserver.h"
#include "nsWeakReference.h"
#include "nsSVGMatrix.h"
#include "nsTextFormatter.h"
#include "nsContentUtils.h"
#include "nsDOMError.h"
////////////////////////////////////////////////////////////////////////
// nsSVGTransform
class nsSVGTransform : public nsIDOMSVGTransform,
public nsSVGValue,
public nsISVGValueObserver
{
public:
static nsresult Create(nsIDOMSVGTransform** aResult);
protected:
nsSVGTransform();
~nsSVGTransform();
nsresult Init();
public:
// nsISupports interface:
NS_DECL_ISUPPORTS
// nsIDOMSVGTransform interface:
NS_DECL_NSIDOMSVGTRANSFORM
// 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);
protected:
nsCOMPtr<nsIDOMSVGMatrix> mMatrix;
float mAngle, mOriginX, mOriginY;
PRUint16 mType;
};
//----------------------------------------------------------------------
// Implementation

View File

@ -40,6 +40,54 @@
#define __NS_SVGTRANSFORM_H__
#include "nsIDOMSVGTransform.h"
#include "nsSVGValue.h"
#include "nsISVGValueObserver.h"
////////////////////////////////////////////////////////////////////////
// nsSVGTransform
class nsSVGTransform : public nsIDOMSVGTransform,
public nsSVGValue,
public nsISVGValueObserver
{
public:
static nsresult Create(nsIDOMSVGTransform** aResult);
protected:
nsSVGTransform();
~nsSVGTransform();
nsresult Init();
public:
// nsISupports interface:
NS_DECL_ISUPPORTS
// nsIDOMSVGTransform interface:
NS_DECL_NSIDOMSVGTRANSFORM
// 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);
#ifdef MOZ_SMIL
// Additional methods needed for animation
void GetRotationOrigin(float& aOriginX, float& aOriginY) const
{
aOriginX = mOriginX;
aOriginY = mOriginY;
}
#endif // MOZ_SMIL
protected:
nsCOMPtr<nsIDOMSVGMatrix> mMatrix;
float mAngle, mOriginX, mOriginY;
PRUint16 mType;
};
nsresult
NS_NewSVGTransform(nsIDOMSVGTransform** result);

View File

@ -0,0 +1,439 @@
/* -*- 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 <birtles@gmail.com>
*
* 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"
nsISMILType*
nsSVGTransformSMILAttr::GetSMILType() const
{
return &nsSVGTransformSMILType::sSingleton;
}
nsresult
nsSVGTransformSMILAttr::ValueFromString(const nsAString& aStr,
const nsISMILAnimationElement* aSrcElement,
nsSMILValue& aValue) const
{
NS_ENSURE_TRUE(aSrcElement, NS_ERROR_FAILURE);
NS_ASSERTION(aValue.IsNull(),
"aValue should have been cleared before calling ValueFromString.");
nsSMILValue val(&nsSVGTransformSMILType::sSingleton);
if (val.IsNull())
return NS_ERROR_FAILURE;
const nsAttrValue* typeAttr = aSrcElement->GetAnimAttr(nsGkAtoms::type);
const nsIAtom* transformType = typeAttr
? typeAttr->GetAtomValue()
: nsGkAtoms::translate;
nsresult rv = ParseValue(aStr, transformType, val);
if (NS_FAILED(rv))
return rv;
aValue = val;
return NS_OK;
}
nsSMILValue
nsSVGTransformSMILAttr::GetBaseValue() const
{
nsSVGTransformSMILType *type = &nsSVGTransformSMILType::sSingleton;
nsSMILValue val(type);
if (val.IsNull())
return val;
nsIDOMSVGTransformList *list = mVal->mBaseVal.get();
PRUint32 numItems = 0;
list->GetNumberOfItems(&numItems);
for (PRUint32 i = 0; i < numItems; i++) {
nsCOMPtr<nsIDOMSVGTransform> transform;
nsresult rv = list->GetItem(i, getter_AddRefs(transform));
if (NS_SUCCEEDED(rv) && transform) {
rv = AppendSVGTransformToSMILValue(transform.get(), val);
NS_ENSURE_SUCCESS(rv,nsSMILValue());
}
}
return val;
}
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
mVal->WillModify(nsISVGValue::mod_other);
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);
mVal->DidModify(nsISVGValue::mod_other);
return NS_OK;
}
//----------------------------------------------------------------------
// Implementation helpers
nsresult
nsSVGTransformSMILAttr::ParseValue(const nsAString& aSpec,
const nsIAtom* aTransformType,
nsSMILValue& aResult) const
{
nsSVGTransformSMILType* type = &nsSVGTransformSMILType::sSingleton;
NS_ASSERTION(
type == static_cast<nsSVGTransformSMILType const *>(aResult.mType),
"Unexpected type for SMIL value result.");
// Reset the result so we can just append to it
nsresult rv = type->Init(aResult);
NS_ENSURE_SUCCESS(rv,rv);
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 NS_ERROR_FAILURE;
transformType = nsSVGSMILTransform::TRANSFORM_TRANSLATE;
} else if (aTransformType == nsGkAtoms::scale) {
// sx [sy=sx]
if (numParsed != 1 && numParsed != 2)
return NS_ERROR_FAILURE;
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 NS_ERROR_FAILURE;
transformType = nsSVGSMILTransform::TRANSFORM_ROTATE;
} else if (aTransformType == nsGkAtoms::skewX) {
// x-angle
if (numParsed != 1)
return NS_ERROR_FAILURE;
transformType = nsSVGSMILTransform::TRANSFORM_SKEWX;
} else if (aTransformType == nsGkAtoms::skewY) {
// y-angle
if (numParsed != 1)
return NS_ERROR_FAILURE;
transformType = nsSVGSMILTransform::TRANSFORM_SKEWY;
} else {
return NS_ERROR_FAILURE;
}
return type->AppendTransform(nsSVGSMILTransform(transformType, params),
aResult);
}
inline PRBool
nsSVGTransformSMILAttr::IsSpace(const char c) const
{
return (c == 0x9 || c == 0xA || c == 0xD || c == 0x20);
}
inline void
nsSVGTransformSMILAttr::SkipWsp(nsACString::const_iterator& aIter,
const nsACString::const_iterator& aIterEnd) const
{
while (aIter != aIterEnd && IsSpace(*aIter))
++aIter;
}
PRInt32
nsSVGTransformSMILAttr::ParseParameterList(const nsAString& aSpec,
float* aVars,
PRInt32 aNVars) const
{
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())
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) const
{
nsSVGTransformSMILType* type = &nsSVGTransformSMILType::sSingleton;
PRUint16 svgTransformType = nsIDOMSVGTransform::SVG_TRANSFORM_MATRIX;
aTransform->GetType(&svgTransformType);
nsCOMPtr<nsIDOMSVGMatrix> matrix;
nsresult rv = aTransform->GetMatrix(getter_AddRefs(matrix));
if (NS_FAILED(rv) || !matrix)
return NS_ERROR_FAILURE;
float params[3] = { 0.f };
nsSVGSMILTransform::TransformType transformType;
switch (svgTransformType)
{
case nsIDOMSVGTransform::SVG_TRANSFORM_TRANSLATE:
{
matrix->GetE(&params[0]);
matrix->GetF(&params[1]);
transformType = nsSVGSMILTransform::TRANSFORM_TRANSLATE;
}
break;
case nsIDOMSVGTransform::SVG_TRANSFORM_SCALE:
{
matrix->GetA(&params[0]);
matrix->GetD(&params[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<nsSVGTransform*>(aTransform);
svgTransform->GetAngle(&params[0]);
svgTransform->GetRotationOrigin(params[1], params[2]);
transformType = nsSVGSMILTransform::TRANSFORM_ROTATE;
}
break;
case nsIDOMSVGTransform::SVG_TRANSFORM_SKEWX:
{
aTransform->GetAngle(&params[0]);
transformType = nsSVGSMILTransform::TRANSFORM_SKEWX;
}
break;
case nsIDOMSVGTransform::SVG_TRANSFORM_SKEWY:
{
aTransform->GetAngle(&params[0]);
transformType = nsSVGSMILTransform::TRANSFORM_SKEWY;
}
break;
case nsIDOMSVGTransform::SVG_TRANSFORM_MATRIX:
{
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]);
rv = type->AppendTransform(nsSVGSMILTransform(mx), aValue);
transformType = nsSVGSMILTransform::TRANSFORM_MATRIX;
}
break;
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;
}
if (transformType != nsSVGSMILTransform::TRANSFORM_MATRIX) {
rv =
type->AppendTransform(nsSVGSMILTransform(transformType, params), aValue);
}
return rv;
}
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<nsIDOMSVGTransform> 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<nsIDOMSVGTransform> 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<nsIDOMSVGTransform> removed;
rv = aTransformList->RemoveItem(--svgLength, getter_AddRefs(removed));
NS_ENSURE_SUCCESS(rv,rv);
}
return NS_OK;
}
nsresult
nsSVGTransformSMILAttr::GetSVGTransformFromSMILValue(
const nsSVGSMILTransform& aSMILTransform,
nsIDOMSVGTransform* aSVGTransform) const
{
nsresult rv = NS_ERROR_FAILURE;
switch (aSMILTransform.mTransformType)
{
case nsSVGSMILTransform::TRANSFORM_TRANSLATE:
rv = aSVGTransform->SetTranslate(aSMILTransform.mParams[0],
aSMILTransform.mParams[1]);
break;
case nsSVGSMILTransform::TRANSFORM_SCALE:
rv = aSVGTransform->SetScale(aSMILTransform.mParams[0],
aSMILTransform.mParams[1]);
break;
case nsSVGSMILTransform::TRANSFORM_ROTATE:
rv = aSVGTransform->SetRotate(aSMILTransform.mParams[0],
aSMILTransform.mParams[1],
aSMILTransform.mParams[2]);
break;
case nsSVGSMILTransform::TRANSFORM_SKEWX:
rv = aSVGTransform->SetSkewX(aSMILTransform.mParams[0]);
break;
case nsSVGSMILTransform::TRANSFORM_SKEWY:
rv = aSVGTransform->SetSkewY(aSMILTransform.mParams[0]);
break;
case nsSVGSMILTransform::TRANSFORM_MATRIX:
{
nsCOMPtr<nsIDOMSVGMatrix> svgMatrix;
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_ENSURE_TRUE(svgMatrix,NS_ERROR_FAILURE);
rv = aSVGTransform->SetMatrix(svgMatrix);
}
break;
}
return rv;
}

View File

@ -0,0 +1,95 @@
/* -*- 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 <birtles@gmail.com>
*
* 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 nsISMILType* GetSMILType() const;
virtual nsresult ValueFromString(const nsAString& aStr,
const nsISMILAnimationElement* aSrcElement,
nsSMILValue& aValue) const;
virtual nsSMILValue GetBaseValue() const;
virtual nsresult SetAnimValue(const nsSMILValue& aValue);
protected:
nsresult ParseValue(const nsAString& aSpec,
const nsIAtom* aTransformType,
nsSMILValue& aResult) const;
PRInt32 ParseParameterList(const nsAString& aSpec, float* aVars,
PRInt32 aNVars) const;
PRBool IsSpace(const char c) const;
void SkipWsp(nsACString::const_iterator& aIter,
const nsACString::const_iterator& aIterEnd) const;
nsresult AppendSVGTransformToSMILValue(nsIDOMSVGTransform* transform,
nsSMILValue& aValue) const;
nsresult UpdateFromSMILValue(nsIDOMSVGTransformList* aTransformList,
const nsSMILValue& aValue);
nsresult GetSVGTransformFromSMILValue(
const nsSVGSMILTransform& aSMILTransform,
nsIDOMSVGTransform* aSVGTransform) const;
already_AddRefed<nsIDOMSVGTransform> GetSVGTransformFromSMILValue(
const nsSMILValue& aValue) const;
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_

View File

@ -0,0 +1,356 @@
/* -*- 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 <birtles@gmail.com>
*
* 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 "nsSVGTransformSMILType.h"
#include "nsSMILValue.h"
#include "nsCRT.h"
#include <math.h>
/*static*/ nsSVGTransformSMILType nsSVGTransformSMILType::sSingleton;
//----------------------------------------------------------------------
// nsISMILType implementation
nsresult
nsSVGTransformSMILType::Init(nsSMILValue &aValue) const
{
NS_PRECONDITION(aValue.mType == this || aValue.IsNull(),
"Unexpected value type");
NS_ASSERTION(aValue.mType != this || aValue.mU.mPtr,
"Invalid nsSMILValue of SVG transform type: NULL data member.");
if (aValue.mType != this || !aValue.mU.mPtr) {
// Different type, or no data member: allocate memory and set type
TransformArray* transforms = new TransformArray(1);
NS_ENSURE_TRUE(transforms, NS_ERROR_OUT_OF_MEMORY);
aValue.mU.mPtr = transforms;
aValue.mType = this;
} else {
// Same type, just set clear
TransformArray* transforms = static_cast<TransformArray*>(aValue.mU.mPtr);
transforms->Clear();
}
return NS_OK;
}
void
nsSVGTransformSMILType::Destroy(nsSMILValue& aValue) const
{
NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value type.");
TransformArray* params = static_cast<TransformArray*>(aValue.mU.mPtr);
delete params;
aValue.mU.mPtr = nsnull;
aValue.mType = &nsSMILNullType::sSingleton;
}
nsresult
nsSVGTransformSMILType::Assign(nsSMILValue& aDest,
const nsSMILValue& aSrc) const
{
NS_PRECONDITION(aDest.mType == aSrc.mType, "Incompatible SMIL types.");
NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL value.");
const TransformArray* srcTransforms =
static_cast<const TransformArray*>(aSrc.mU.mPtr);
TransformArray* dstTransforms = static_cast<TransformArray*>(aDest.mU.mPtr);
// Before we assign, ensure we have sufficient memory
PRBool result = dstTransforms->SetCapacity(srcTransforms->Length());
NS_ENSURE_TRUE(result,NS_ERROR_OUT_OF_MEMORY);
*dstTransforms = *srcTransforms;
return NS_OK;
}
nsresult
nsSVGTransformSMILType::Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
PRUint32 aCount) const
{
NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL type.");
NS_PRECONDITION(aDest.mType == aValueToAdd.mType, "Incompatible SMIL types.");
TransformArray& dstTransforms(*static_cast<TransformArray*>(aDest.mU.mPtr));
const TransformArray& srcTransforms
(*static_cast<const TransformArray*>(aValueToAdd.mU.mPtr));
// We're doing a simple add here (as opposed to a sandwich add below).
// We only do this when we're accumulating a repeat result or calculating
// a by-animation value.
//
// In either case we should have 1 transform in the source array.
NS_ASSERTION(srcTransforms.Length() == 1,
"Invalid source transform list to add.");
// And we should have 0 or 1 transforms in the dest array.
// (We can have 0 transforms in the case of by-animation when we are
// calculating the by-value as "0 + by". Zero being represented by an
// nsSMILValue with an empty transform array.)
NS_ASSERTION(dstTransforms.Length() < 2,
"Invalid dest transform list to add to.");
// Get the individual transforms to add
const nsSVGSMILTransform& srcTransform = srcTransforms[0];
if (dstTransforms.IsEmpty()) {
nsSVGSMILTransform* result = dstTransforms.AppendElement(
nsSVGSMILTransform(srcTransform.mTransformType));
NS_ENSURE_TRUE(result,NS_ERROR_OUT_OF_MEMORY);
}
nsSVGSMILTransform& dstTransform = dstTransforms[0];
// The types must be the same
NS_ASSERTION(srcTransform.mTransformType == dstTransform.mTransformType,
"Trying to perform simple add of different transform types.");
// And it should be impossible that one of them is of matrix type
NS_ASSERTION(
srcTransform.mTransformType != nsSVGSMILTransform::TRANSFORM_MATRIX,
"Trying to perform simple add with matrix transform.");
// Add the parameters
for (int i = 0; i <= 2; ++i) {
dstTransform.mParams[i] += srcTransform.mParams[i] * aCount;
}
return NS_OK;
}
nsresult
nsSVGTransformSMILType::SandwichAdd(nsSMILValue& aDest,
const nsSMILValue& aValueToAdd) const
{
NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL type.");
NS_PRECONDITION(aDest.mType == aValueToAdd.mType, "Incompatible SMIL types.");
// For <animateTransform> a sandwich add means a matrix post-multiplication
// which just means to put the additional transform on the end of the array
TransformArray& dstTransforms(*static_cast<TransformArray*>(aDest.mU.mPtr));
const TransformArray& srcTransforms
(*static_cast<const TransformArray*>(aValueToAdd.mU.mPtr));
// We're only expecting to be adding 1 src transform on to the list
NS_ASSERTION(srcTransforms.Length() == 1,
"Trying to do sandwich add of more than one value.");
// Stick the src on the end of the array
const nsSVGSMILTransform& srcTransform = srcTransforms[0];
nsSVGSMILTransform* result = dstTransforms.AppendElement(srcTransform);
NS_ENSURE_TRUE(result,NS_ERROR_OUT_OF_MEMORY);
return NS_OK;
}
nsresult
nsSVGTransformSMILType::ComputeDistance(const nsSMILValue& aFrom,
const nsSMILValue& aTo,
double& aDistance) const
{
NS_PRECONDITION(aFrom.mType == aTo.mType,
"Can't compute difference between different SMIL types.");
NS_PRECONDITION(aFrom.mType == this, "Unexpected SMIL type.");
const TransformArray* fromTransforms =
static_cast<const TransformArray*>(aFrom.mU.mPtr);
const TransformArray* toTransforms =
static_cast<const TransformArray*>(aTo.mU.mPtr);
// ComputeDistance is only used for calculating distances between single
// values in a values array which necessarily have the same type
//
// So we should only have one transform in each array and they should be of
// the same type
NS_ASSERTION(fromTransforms->Length() == 1,
"Wrong number of elements in from value.");
NS_ASSERTION(toTransforms->Length() == 1,
"Wrong number of elements in to value.");
const nsSVGSMILTransform& fromTransform = (*fromTransforms)[0];
const nsSVGSMILTransform& toTransform = (*toTransforms)[0];
NS_ASSERTION(fromTransform.mTransformType == toTransform.mTransformType,
"Incompatible transform types to calculate distance between.");
switch (fromTransform.mTransformType)
{
// We adopt the SVGT1.2 notions of distance here
// See: http://www.w3.org/TR/SVGTiny12/animate.html#complexDistances
// (As discussed in bug #469040)
case nsSVGSMILTransform::TRANSFORM_TRANSLATE:
case nsSVGSMILTransform::TRANSFORM_SCALE:
{
const float& a_tx = fromTransform.mParams[0];
const float& a_ty = fromTransform.mParams[1];
const float& b_tx = toTransform.mParams[0];
const float& b_ty = toTransform.mParams[1];
aDistance = sqrt(pow(a_tx - b_tx, 2) + (pow(a_ty - b_ty, 2)));
}
break;
case nsSVGSMILTransform::TRANSFORM_ROTATE:
case nsSVGSMILTransform::TRANSFORM_SKEWX:
case nsSVGSMILTransform::TRANSFORM_SKEWY:
{
const float& a = fromTransform.mParams[0];
const float& b = toTransform.mParams[0];
aDistance = fabs(a-b);
}
break;
default:
NS_ERROR("Got bad transform types for calculating distances.");
aDistance = 1.0;
return NS_ERROR_FAILURE;
}
return NS_OK;
}
nsresult
nsSVGTransformSMILType::Interpolate(const nsSMILValue& aStartVal,
const nsSMILValue& aEndVal,
double aUnitDistance,
nsSMILValue& aResult) const
{
NS_PRECONDITION(aStartVal.mType == aEndVal.mType,
"Can't interpolate between different SMIL types.");
NS_PRECONDITION(aStartVal.mType == this,
"Unexpected type for interpolation.");
NS_PRECONDITION(aResult.mType == this, "Unexpected result type.");
const TransformArray& startTransforms =
(*static_cast<const TransformArray*>(aStartVal.mU.mPtr));
const TransformArray& endTransforms
(*static_cast<const TransformArray*>(aEndVal.mU.mPtr));
// We may have 0..n transforms in the start transform array (the base
// value) but we should only have 1 transform in the end transform array
NS_ASSERTION(endTransforms.Length() == 1,
"Invalid end-point for interpolating between transform values.");
// The end point should never be a matrix transform
const nsSVGSMILTransform& endTransform = endTransforms[0];
NS_ASSERTION(
endTransform.mTransformType != nsSVGSMILTransform::TRANSFORM_MATRIX,
"End point for interpolation should not be a matrix transform.");
// If we have 0 or more than 1 transform in the start transform array then we
// just interpolate from 0, 0, 0
// Likewise, even if there's only 1 transform in the start transform array
// then if the type of the start transform doesn't match the end then we
// can't interpolate and should just use 0, 0, 0
static float identityParams[3] = { 0.f };
const float* startParams = nsnull;
if (startTransforms.Length() == 1) {
const nsSVGSMILTransform& startTransform = startTransforms[0];
if (startTransform.mTransformType == endTransform.mTransformType) {
startParams = startTransform.mParams;
}
}
if (!startParams) {
startParams = identityParams;
}
const float* endParams = endTransform.mParams;
// Interpolate between the params
float newParams[3];
for (int i = 0; i <= 2; ++i) {
const float& a = startParams[i];
const float& b = endParams[i];
newParams[i] = a + (b - a) * aUnitDistance;
}
// Make the result
nsSVGSMILTransform resultTransform(endTransform.mTransformType, newParams);
// Clear the way for it in the result array
TransformArray& dstTransforms =
(*static_cast<TransformArray*>(aResult.mU.mPtr));
dstTransforms.Clear();
// Assign the result
nsSVGSMILTransform* transform = dstTransforms.AppendElement(resultTransform);
NS_ENSURE_TRUE(transform,NS_ERROR_OUT_OF_MEMORY);
return NS_OK;
}
//----------------------------------------------------------------------
// Transform array accessors
PRUint32
nsSVGTransformSMILType::GetNumTransforms(const nsSMILValue& aValue) const
{
NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value.");
const TransformArray& transforms =
*static_cast<const TransformArray*>(aValue.mU.mPtr);
return transforms.Length();
}
const nsSVGSMILTransform*
nsSVGTransformSMILType::GetTransformAt(PRUint32 aIndex,
const nsSMILValue& aValue) const
{
NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value.");
const TransformArray& transforms =
*static_cast<const TransformArray*>(aValue.mU.mPtr);
if (aIndex >= transforms.Length()) {
NS_ERROR("Attempting to access invalid transform.");
return nsnull;
}
return &transforms[aIndex];
}
nsresult
nsSVGTransformSMILType::AppendTransform(const nsSVGSMILTransform& aTransform,
nsSMILValue& aValue) const
{
NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value.");
TransformArray& transforms = *static_cast<TransformArray*>(aValue.mU.mPtr);
nsSVGSMILTransform* transform = transforms.AppendElement(aTransform);
NS_ENSURE_TRUE(transform,NS_ERROR_OUT_OF_MEMORY);
return NS_OK;
}

View File

@ -0,0 +1,141 @@
/* -*- 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 <birtles@gmail.com>
*
* 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_SVGTRANSFORMSMILTYPE_H_
#define NS_SVGTRANSFORMSMILTYPE_H_
#include "nsISMILType.h"
#include "nsSVGSMILTransform.h"
#include "nsTArray.h"
struct nsSMILValue;
////////////////////////////////////////////////////////////////////////
// nsSVGTransformSMILType
//
// Operations for animating an nsSVGTransformList.
//
// This class is confused somewhat by the fact that:
// (i) An <animateTransform> element animates an SVGTransformList
// (ii) BUT <animateTransform> only allows the user to specify animation values
// for an SVGTransform
//
// This may be rectified in a future edition of SVG but for now it means that
// the underlying value of an animation may be something of the form:
//
// rotate(90) scale(2) skewX(50)
//
// BUT the animation values can only ever be SINGLE transform operations such as
//
// rotate(90)
//
// (actually the syntax here is:
// <animateTransform type="rotate" from="0" to="90"...
// OR maybe
// <animateTransform type="rotate" values="0; 90; 30; 50"...
// OR even (with a rotation centre)
// <animateTransform type="rotate" values="0 50 20; 30 50 20; 70 0 0"...)
//
// This has many implications for the number of elements we expect in the
// transform array supplied for each operation.
//
// For example, Add() only ever operates on the values specified on an
// <animateTransform> element and so these values can only ever contain 0 or
// 1 TRANSFORM elements as the syntax doesn't allow more. (A "value" here is
// a single element in the values array such as "0 50 20" above.)
//
// Likewise ComputeDistance() only ever operates within the values specified on
// an <animateTransform> element so similar conditions hold.
//
// However, SandwichAdd() combines with a base value which may contain 0..n
// transforms either because the base value of the attribute specifies a series
// of transforms, e.g.
//
// <circle transform="translate(30) rotate(50)"... >
// <animateTransform.../>
// </circle>
//
// or because several animations target the same attribute and are additive and
// so are simply appended on to the transformation array, e.g.
//
// <circle transform="translate(30)"... >
// <animateTransform type="rotate" additive="sum".../>
// <animateTransform type="scale" additive="sum".../>
// <animateTransform type="skewX" additive="sum".../>
// </circle>
//
// Similar conditions hold for Interpolate() which in cases such as to-animation
// may have use a start-value the base value of the target attribute (which as
// we have seen above can contain 0..n elements) whilst the end-value comes from
// the <animateTransform> and so can only hold 1 transform.
//
class nsSVGTransformSMILType : public nsISMILType
{
public:
// nsISMILType
virtual nsresult Init(nsSMILValue& aValue) const;
virtual void Destroy(nsSMILValue& aValue) const;
virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
virtual nsresult Add(nsSMILValue& aDest,
const nsSMILValue& aValueToAdd,
PRUint32 aCount) const;
virtual nsresult SandwichAdd(nsSMILValue& aDest,
const nsSMILValue& aValueToAdd) const;
virtual nsresult ComputeDistance(const nsSMILValue& aFrom,
const nsSMILValue& aTo,
double& aDistance) const;
virtual nsresult Interpolate(const nsSMILValue& aStartVal,
const nsSMILValue& aEndVal,
double aUnitDistance,
nsSMILValue& aResult) const;
// Transform array accessors
PRUint32 GetNumTransforms(const nsSMILValue& aValue) const;
const nsSVGSMILTransform* GetTransformAt(PRUint32 aIndex,
const nsSMILValue& aValue) const;
nsresult AppendTransform(const nsSVGSMILTransform& aTransform,
nsSMILValue& aValue) const;
static nsSVGTransformSMILType sSingleton;
protected:
typedef nsTArray<nsSVGSMILTransform> TransformArray;
private:
nsSVGTransformSMILType() {}
};
#endif // NS_SVGTRANSFORMSMILTYPE_H_

View File

@ -131,6 +131,7 @@ XPIDLSRCS = \
ifdef MOZ_SMIL
XPIDLSRCS += \
nsIDOMSVGAnimateElement.idl \
nsIDOMSVGAnimateTransformElement.idl \
nsIDOMSVGAnimationElement.idl \
nsIDOMSVGSetElement.idl \
$(NULL)

View File

@ -0,0 +1,41 @@
/* -*- Mode: IDL; 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) 2005
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brian Birtles <birtles@gmail.com>
*
* 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 "nsIDOMSVGAnimationElement.idl"
[scriptable, uuid(735e0f75-c6aa-4aee-bcd2-46426d6ac90c)]
interface nsIDOMSVGAnimateTransformElement : nsIDOMSVGAnimationElement {};

View File

@ -245,6 +245,7 @@ enum nsDOMClassInfoID {
eDOMClassInfo_SVGAElement_id,
#ifdef MOZ_SMIL
eDOMClassInfo_SVGAnimateElement_id,
eDOMClassInfo_SVGAnimateTransformElement_id,
eDOMClassInfo_SVGSetElement_id,
#endif // MOZ_SMIL
eDOMClassInfo_SVGCircleElement_id,

View File

@ -378,6 +378,7 @@
#include "nsIDOMSVGAnimatedString.h"
#ifdef MOZ_SMIL
#include "nsIDOMSVGAnimateElement.h"
#include "nsIDOMSVGAnimateTransformElement.h"
#include "nsIDOMSVGSetElement.h"
#include "nsIDOMSVGAnimationElement.h"
#include "nsIDOMElementTimeControl.h"
@ -948,6 +949,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
#ifdef MOZ_SMIL
NS_DEFINE_CLASSINFO_DATA(SVGAnimateElement, nsElementSH,
ELEMENT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(SVGAnimateTransformElement, nsElementSH,
ELEMENT_SCRIPTABLE_FLAGS)
NS_DEFINE_CLASSINFO_DATA(SVGSetElement, nsElementSH,
ELEMENT_SCRIPTABLE_FLAGS)
#endif // MOZ_SMIL
@ -2771,6 +2774,14 @@ nsDOMClassInfo::Init()
DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(SVGAnimateTransformElement,
nsIDOMSVGAnimateTransformElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGAnimationElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGAnimateTransformElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMElementTimeControl)
DOM_CLASSINFO_SVG_ELEMENT_MAP_ENTRIES
DOM_CLASSINFO_MAP_END
DOM_CLASSINFO_MAP_BEGIN(SVGSetElement,
nsIDOMSVGSetElement)
DOM_CLASSINFO_MAP_ENTRY(nsIDOMSVGAnimationElement)

View File

@ -19,6 +19,9 @@ include sort/reftest.list
# style tests
include style/reftest.list
# animateTransform tests
include transform/reftest.list
# time-dependent tests
# XXXdholbert Disabling this class of tests for now, because most of them
# can & should be converted so they don't depend on specific timeout values.

View File

@ -0,0 +1,42 @@
<svg xmlns="http://www.w3.org/2000/svg">
<g transform="translate(50 50)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
<g transform="translate(150 50)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
<g transform="translate(250 50)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
<g transform="translate(50 150)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
<g transform="translate(150 150)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
<g transform="translate(250 150)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
<g transform="translate(50 250)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
<g transform="translate(150 250)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
<g transform="translate(250 250)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
<g transform="translate(50 350)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,209 @@
<svg xmlns="http://www.w3.org/2000/svg"
class="reftest-wait"
onload="setupSnapshot(1.5)">
<script type="text/ecmascript"><![CDATA[
function setupSnapshot(timeInSeconds) {
var svg = document.documentElement;
svg.pauseAnimations();
svg.setCurrentTime(timeInSeconds);
// Use setTimeout to allow SMIL to update the animation before we check
// the values and take a snapshot
setTimeout('checkAnimVals()');
}
function checkAnimVals() {
var svg = document.documentElement;
var paths = svg.getElementsByTagName("path");
for (var i = 0; i < paths.length; i++) {
var path = paths[i];
checkAnimVal(path, path.transform.animVal, i);
}
svg.removeAttribute("class");
}
function Transform(type, angle) {
this.type = type;
this.angle = angle;
}
function checkAnimVal(path, val, index) {
var expected = [];
switch (index) {
case 0:
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_ROTATE, 90));
break;
case 1:
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_ROTATE, 90));
break;
case 2:
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_ROTATE, -90));
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_ROTATE, 180));
break;
case 3:
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_ROTATE, 45));
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_ROTATE, 45));
break;
case 4:
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_TRANSLATE, 0));
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_ROTATE, 90));
break;
case 5:
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_ROTATE, -90));
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_ROTATE, 90));
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_ROTATE, 90));
break;
case 6:
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_TRANSLATE, 0));
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_ROTATE, 45));
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_ROTATE, 45));
break;
case 7:
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_SKEWX, 20));
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_TRANSLATE, 0));
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_ROTATE, 45));
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_ROTATE, 45));
break;
case 8:
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_SKEWX, 20));
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_TRANSLATE, 0));
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_ROTATE, 45));
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_TRANSLATE, 0));
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_TRANSLATE, 0));
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_ROTATE, 45));
break;
case 9:
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_ROTATE, 90));
expected.push(new Transform(SVGTransform.SVG_TRANSFORM_TRANSLATE, 0));
break;
}
var ok = true;
if (val.numberOfItems == expected.length) {
for (var i = 0; i < val.numberOfItems; i++) {
var transform = val.getItem(i);
if (transform.type != expected[i].type ||
transform.angle != expected[i].angle) {
ok = false;
}
}
} else {
ok = false;
}
if (!ok) {
path.style.visibility = 'hidden';
}
}
]]></script>
<!-- not additive -->
<g transform="translate(50 50)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(-90)">
<animateTransform attributeName="transform"
type="rotate" from="0" to="90" dur="1s" fill="freeze"/>
</path>
</g>
<!-- to-animation: special additive -->
<g transform="translate(150 50)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(-90)">
<animateTransform attributeName="transform"
type="rotate" to="90" dur="1s" fill="freeze"/>
</path>
</g>
<!-- by-animation: special additive -->
<g transform="translate(250 50)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(-90)">
<animateTransform attributeName="transform"
type="rotate" by="180" dur="1s" fill="freeze"/>
</path>
</g>
<!-- normal additive: same type -->
<g transform="translate(50 150)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(45)">
<animateTransform attributeName="transform"
type="rotate" from="0" to="45" dur="1s" fill="freeze"
additive="sum"/>
</path>
</g>
<!-- normal additive: different type -->
<g transform="translate(100 150)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="translate(50)">
<animateTransform attributeName="transform"
type="rotate" from="0" to="90" dur="1s" fill="freeze"
additive="sum"/>
</path>
</g>
<!-- stacked additive: same type -->
<g transform="translate(250 150)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(-90)">
<animateTransform attributeName="transform"
type="rotate" from="0" to="90" dur="1s" fill="freeze"
additive="sum"/>
<animateTransform attributeName="transform"
type="rotate" from="0" to="90" dur="1s" fill="freeze"
additive="sum"/>
</path>
</g>
<!-- stacked additive: different types #1 -->
<g transform="translate(0 250)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="translate(50)">
<animateTransform attributeName="transform"
type="rotate" from="0" to="45" dur="1s" fill="freeze"
additive="sum"/>
<animateTransform attributeName="transform"
type="rotate" from="0" to="45" dur="1s" fill="freeze"
additive="sum"/>
</path>
</g>
<!-- stacked additive: different types #2 -->
<g transform="translate(100 250) skewX(-20)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="skewX(20) translate(50)">
<animateTransform attributeName="transform"
type="rotate" from="0" to="45" dur="1s" fill="freeze"
additive="sum"/>
<animateTransform attributeName="transform"
type="rotate" from="0" to="45" dur="1s" fill="freeze"
additive="sum"/>
</path>
</g>
<!-- stacked additive: different types #3 -->
<g transform="translate(200 250) skewX(-20)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="skewX(20) translate(50)">
<animateTransform attributeName="transform"
type="rotate" from="0" to="45" dur="1s" fill="freeze"
additive="sum"/>
<animateTransform attributeName="transform"
type="translate" from="0" to="30" dur="1s" fill="freeze"
additive="sum"/>
<animateTransform attributeName="transform"
type="translate" from="0" to="-30" dur="1s" fill="freeze"
additive="sum"/>
<animateTransform attributeName="transform"
type="rotate" from="0" to="45" dur="1s" fill="freeze"
additive="sum"/>
</path>
</g>
<!-- base value with rotation around a centre -->
<g transform="translate(-50 300)">
<path d="M48 100h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90 50 50)">
<animateTransform attributeName="transform"
type="translate" from="0 0" to="0 -50" dur="1s" fill="freeze"
additive="sum"/>
</path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -0,0 +1,31 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<g id="smiley">
<circle fill="yellow" stroke="black" stroke-width="2" cx="0" cy="0"
r="40"/>
<circle fill="white" stroke="black" stroke-width="1" cx="-14" cy="-14"
r="14"/>
<circle fill="white" stroke="black" stroke-width="1" cx="14" cy="-14"
r="14"/>
<circle cx="-10" cy="-14" r="4"/>
<circle cx="10" cy="-14" r="4"/>
<path d="m-11 14a13,13 0 0,0 22,0" fill="none" stroke="black"/>
</g>
</defs>
<g transform="translate(50 50)">
<use xlink:href="#smiley"/>
</g>
<g transform="translate(150 50)">
<use xlink:href="#smiley"/>
</g>
<g transform="translate(250 50)">
<use xlink:href="#smiley"/>
</g>
<g transform="translate(50 150)">
<use xlink:href="#smiley"/>
</g>
<g transform="translate(150 150)">
<use xlink:href="#smiley"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 946 B

View File

@ -0,0 +1,64 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="setTimeAndSnapshot(1, true)">
<script xlink:href="../smil-util.js" type="text/javascript"/>
<defs>
<g id="smiley">
<circle fill="yellow" stroke="black" stroke-width="2" cx="0" cy="0"
r="40"/>
<circle fill="white" stroke="black" stroke-width="1" cx="-14" cy="-14"
r="14"/>
<circle fill="white" stroke="black" stroke-width="1" cx="14" cy="-14"
r="14"/>
<circle cx="-10" cy="-14" r="4"/>
<circle cx="10" cy="-14" r="4"/>
<path d="m-11 14a13,13 0 0,0 22,0" fill="none" stroke="black"/>
</g>
</defs>
<!-- translation -->
<g transform="translate(0 50)">
<use xlink:href="#smiley">
<animateTransform attributeName="transform" attributeType="XML"
type="translate" fill="freeze" dur="2s" calcMode="paced"
values="-5 -10; 35 20; 95 -60"/>
</use>
</g>
<!-- rotation -->
<g transform="translate(150 50) rotate(-90)">
<use xlink:href="#smiley">
<animateTransform attributeName="transform" attributeType="XML"
type="rotate" fill="freeze" dur="2s" calcMode="paced"
values="20 10 10; 40 -15 25; 160 21 -35"/>
</use>
</g>
<!-- skewY -->
<g transform="translate(250 50) skewY(-30)">
<use xlink:href="#smiley">
<animateTransform attributeName="transform" attributeType="XML"
type="skewY" fill="freeze" dur="2s" calcMode="paced"
values="10; 40; 50"/>
</use>
</g>
<!-- scale -->
<g transform="translate(50 150) scale(0.5)">
<use xlink:href="#smiley">
<animateTransform attributeName="transform" attributeType="XML"
type="scale" fill="freeze" dur="2s" calcMode="paced"
values="-4 -2.5; 4 3.5; 8 0.5"/>
</use>
</g>
<!-- to-animation
You can't have to-animation with a paced calcMode. This test should just
produce regular to-animation without any assertions. This is a white-box
test.
-->
<g transform="translate(100 150)">
<use xlink:href="#smiley">
<animateTransform attributeName="transform" attributeType="XML"
type="translate" fill="freeze" dur="2s" calcMode="paced"
to="100"/>
</use>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,12 @@
# Tests related to SVG Animation (using SMIL), focusing on the animateTransform
# element.
== rotate-angle-1.svg rotate-angle-ref.svg
== rotate-angle-2.svg rotate-angle-ref.svg
== rotate-angle-3.svg rotate-angle-ref.svg
== rotate-angle-4.svg rotate-angle-ref.svg
== rotate-angle-5.svg rotate-angle-ref.svg
== scale-1.svg scale-1-ref.svg
== skew-1.svg skew-1-ref.svg
== paced-1.svg paced-1-ref.svg
== additive-1.svg additive-1-ref.svg

View File

@ -0,0 +1,60 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="setTimeAndSnapshot(1, true)">
<script xlink:href="../smil-util.js" type="text/javascript"/>
<g transform="translate(50 50) rotate(90)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0" to="0" dur="4s" fill="freeze"/>
</path>
</g>
<g transform="translate(150 50)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0" to="90" dur="1s" fill="freeze"/>
</path>
</g>
<g transform="translate(250 50)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0" to="180" dur="2s" fill="freeze"/>
</path>
</g>
<g transform="translate(50 150)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0" to="270" dur="3s" fill="freeze"/>
</path>
</g>
<g transform="translate(150 150)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0" to="360" dur="4s" fill="freeze"/>
</path>
</g>
<g transform="translate(250 150)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0" to="540" dur="6s" fill="freeze"/>
</path>
</g>
<g transform="translate(50 250)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0" to="3600" dur="40s" fill="freeze"/>
</path>
</g>
<g transform="translate(150 250)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0" to="-270" dur="1s" fill="freeze"/>
</path>
</g>
<g transform="translate(250 250)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0" to="-540" dur="2s" fill="freeze"/>
</path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,60 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="setTimeAndSnapshot(1, true)">
<script xlink:href="../smil-util.js" type="text/javascript"/>
<g transform="translate(44 0) rotate(90 6 50)">
<path d="M4 100h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0 6 50" to="0 6 50" dur="4s" fill="freeze"/>
</path>
</g>
<g transform="translate(144 0)">
<path d="M4 100h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0,6,50" to="90 6 50" dur="1s" fill="freeze"/>
</path>
</g>
<g transform="translate(244,0)">
<path d="M4 100h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0 6 50" to="180,6,50" dur="2s" fill="freeze"/>
</path>
</g>
<g transform="translate(44,100)">
<path d="M4 100h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0,6,50" to="270,6,50" dur="3s" fill="freeze"/>
</path>
</g>
<g transform="translate(144,100)">
<path d="M4 100h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0 6 50" to="360 6 50" dur="4s" fill="freeze"/>
</path>
</g>
<g transform="translate(244,100)">
<path d="M4 100h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0 6 50" to="540 6 50" dur="6s" fill="freeze"/>
</path>
</g>
<g transform="translate(44,200)">
<path d="M4 100h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0 6 50" to="3600 6 50" dur="40s" fill="freeze"/>
</path>
</g>
<g transform="translate(144,200)">
<path d="M4 100h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0 6 50" to="-270 6 50" dur="1s" fill="freeze"/>
</path>
</g>
<g transform="translate(244,200)">
<path d="M4 100h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0 6 50" to="-540 6 50" dur="2s" fill="freeze"/>
</path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,60 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="setTimeAndSnapshot(1, true)">
<script xlink:href="../smil-util.js" type="text/javascript"/>
<g transform="translate(0 0) rotate(90 50 50)">
<path d="M48 100h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0 0 50" to="0 200 50" dur="4s" fill="freeze"/>
</path>
</g>
<g transform="translate(100 0)">
<path d="M48 100h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0 0 50" to="90 50 50" dur="1s" fill="freeze"/>
</path>
</g>
<g transform="translate(200 0)">
<path d="M48 100h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0 0 50" to="180 100 50" dur="2s" fill="freeze"/>
</path>
</g>
<g transform="translate(0 100)">
<path d="M48 100h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0 0 50" to="270 150 50" dur="3s" fill="freeze"/>
</path>
</g>
<g transform="translate(100 100)">
<path d="M48 100h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0 0 50" to="360 200 50" dur="4s" fill="freeze"/>
</path>
</g>
<g transform="translate(200 100)">
<path d="M48 100h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0 0 50" to="540 300 50" dur="6s" fill="freeze"/>
</path>
</g>
<g transform="translate(0 200)">
<path d="M48 100h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0 0 50" to="3600 2000 50" dur="40s" fill="freeze"/>
</path>
</g>
<g transform="translate(100 200)">
<path d="M48 100h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0 0 50" to="-270 50 50" dur="1s" fill="freeze"/>
</path>
</g>
<g transform="translate(200 200)">
<path d="M48 100h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0 0 50" to="-540 100 50" dur="2s" fill="freeze"/>
</path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,79 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="setTimeAndSnapshot(1, true)">
<script xlink:href="../smil-util.js" type="text/javascript"/>
<!-- no animation -->
<g transform="translate(50 50) rotate(90)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"/>
</g>
<!-- accumulate: sum -->
<g transform="translate(150 50)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0" to="45" dur="0.5s" fill="freeze"
repeatCount="4" accumulate="sum"/>
</path>
</g>
<!-- accumulate: none -->
<g transform="translate(250 50)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0" to="270" dur="0.75s" fill="freeze"
repeatCount="2"/>
</path>
</g>
<!-- additive: replace -->
<g transform="translate(50 150)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(-90)">
<animateTransform attributeName="transform"
type="rotate" from="0" to="180" dur="2s" fill="freeze"/>
</path>
</g>
<!-- additive: sum (adding to base value) -->
<g transform="translate(150 150)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(-90)">
<animateTransform attributeName="transform"
type="rotate" from="0" to="270" dur="1.5s" fill="freeze"
additive="sum"/>
</path>
</g>
<!-- additive: sum (adding to other animations) -->
<g transform="translate(250 150)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" from="0" to="60" dur="2s" fill="freeze"/>
<animateTransform attributeName="transform"
type="rotate" from="0" to="60" dur="2s" fill="freeze"
additive="sum"/>
<animateTransform attributeName="transform"
type="rotate" from="0" to="60" dur="2s" fill="freeze"
additive="sum"/>
</path>
</g>
<!-- to animation -->
<g transform="translate(50 250)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(45)">
<animateTransform attributeName="transform"
type="rotate" to="135" dur="2s" fill="freeze"/>
</path>
</g>
<!-- by animation -->
<g transform="translate(150 250)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(45)">
<animateTransform attributeName="transform"
type="rotate" by="90" dur="2s" fill="freeze"/>
</path>
</g>
<!-- values animation -->
<g transform="translate(250 250)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue">
<animateTransform attributeName="transform"
type="rotate" values="0; 135; 0" dur="1.5s" fill="freeze"/>
</path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -0,0 +1,86 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="setTimeAndSnapshot(1, true)">
<script xlink:href="../smil-util.js" type="text/javascript"/>
<!-- Tests to-animation behaviour for a lot of undefined situations.
SVG 1.1 doesn't define what should happen here but the behaviour we
expect is based on other browsers. -->
<!-- to animation: rotation from base value -90 to final value 180 -->
<g transform="translate(50 50)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(-90)">
<animateTransform attributeName="transform"
type="rotate" to="180" dur="1.5s" fill="freeze"/>
</path>
</g>
<!-- to animation: rotation from base value -810 to final value 990 -->
<g transform="translate(150 50)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(-810)">
<animateTransform attributeName="transform"
type="rotate" to="990" dur="2s" fill="freeze"/>
</path>
</g>
<!-- to animation: rotation from base value -180 to final value 90 but with
other animations combined.
What happens here is that the rotation animation can't interpolate from
the base value as it's not a rotation transformation, so instead it
assumes an underlying zero matrix as the base value. (see next comment)
-->
<g transform="translate(250 50)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(-90) translate(0 50) scale(2)">
<animateTransform attributeName="transform"
type="rotate" to="180" dur="2s" fill="freeze" additive="sum"/>
</path>
</g>
<!-- to animation: rotate and scale
Here again the scale animation can't interpolate from its base value
which is of a different type so it assumes a zero matrix NOT an identity
matrix (this is what the SVG WG have decided in the SVGT1.2 Tiny test
suite).
-->
<g transform="translate(50 150) rotate(90)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="scale(2)">
<animateTransform attributeName="transform"
type="rotate" to="180" dur="1s" fill="freeze" additive="sum"/>
<animateTransform attributeName="transform"
type="scale" to="2" dur="2s" fill="freeze" additive="sum"/>
</path>
</g>
<!-- to animation: translate and rotate
Likewise here we end up rotating from 0 to 180 because we can't
interpolate from the underlying translation transformation.
-->
<g transform="translate(150 150)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(-90) translate(0 50) scale(2)">
<animateTransform attributeName="transform"
type="translate" to="0" dur="1s" fill="freeze" additive="sum"/>
<animateTransform attributeName="transform"
type="rotate" to="180" dur="2s" fill="freeze" additive="sum"/>
</path>
</g>
<!-- The following are from the reference image -->
<g transform="translate(250 150)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
<g transform="translate(50 250)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
<g transform="translate(150 250)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
<g transform="translate(250 250)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -0,0 +1,38 @@
<svg xmlns="http://www.w3.org/2000/svg">
<g transform="translate(50 50)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
<g transform="translate(150 50)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
<g transform="translate(250 50)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
<g transform="translate(50 150)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
<g transform="translate(150 150)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
<g transform="translate(250 150)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
<g transform="translate(50 250)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
<g transform="translate(150 250)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
<g transform="translate(250 250)">
<path d="M-2 50h4v -90h4l -6 -10 -6 10h4z" fill="blue"
transform="rotate(90)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,38 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<linearGradient id="grad">
<stop offset="5%" stop-color="#F66"/>
<stop offset="95%" stop-color="#FF6"/>
</linearGradient>
<circle fill="url(#grad)" stroke="black" stroke-width="1" cx="0" cy="0"
r="20" id="circle"/>
</defs>
<g transform="translate(50 50)">
<use xlink:href="#circle" transform="scale(2)"/>
</g>
<g transform="translate(150 50)">
<use xlink:href="#circle" transform="scale(2)"/>
</g>
<g transform="translate(250 50)">
<use xlink:href="#circle" transform="scale(2)"/>
</g>
<g transform="translate(50 150)">
<use xlink:href="#circle" transform="scale(2)"/>
</g>
<g transform="translate(150 150)">
<use xlink:href="#circle" transform="scale(2)"/>
</g>
<g transform="translate(250 150)">
<use xlink:href="#circle" transform="scale(2)"/>
</g>
<g transform="translate(50 250)">
<use xlink:href="#circle" transform="scale(2)"/>
</g>
<g transform="translate(150 250)">
<use xlink:href="#circle" transform="scale(2)"/>
</g>
<g transform="translate(250 250)">
<use xlink:href="#circle" transform="scale(2)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,108 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="setTimeAndSnapshot(1, true)">
<script xlink:href="../smil-util.js" type="text/javascript"/>
<defs>
<linearGradient id="grad">
<stop offset="5%" stop-color="#F66"/>
<stop offset="95%" stop-color="#FF6"/>
</linearGradient>
<circle fill="url(#grad)" stroke="black" stroke-width="1" cx="0" cy="0"
r="20" id="circle"/>
</defs>
<!-- to animation
This should interpolate from 0 (not 1) to 4 to match the behaviour
required by the SVGT1.2 test suite and Opera's behaviour.
-->
<g transform="translate(50 50)">
<use xlink:href="#circle">
<animateTransform attributeName="transform"
type="scale" to="4" dur="2s" fill="freeze"/>
</use>
</g>
<!-- from-to animation -->
<g transform="translate(150 50)">
<use xlink:href="#circle">
<animateTransform attributeName="transform"
type="scale" from="-5" to="9" dur="2s" fill="freeze"/>
</use>
</g>
<!-- negative to-animation
Should go from 0 to -4 over 2s, therefore at t=1s, the scale factor
should be -2, so we add a rotation animation to correct the gradient
-->
<g transform="translate(250 50)">
<use xlink:href="#circle">
<animateTransform attributeName="transform"
type="scale" to="-4" dur="2s" fill="freeze"/>
<animateTransform attributeName="transform"
type="rotate" from="0" to="360" dur="2s" fill="freeze" additive="sum"/>
</use>
</g>
<!-- by animation
The behaviour at this point is not clear. The definition of by-animation
is:
"simple animation in which the animation function is defined to offset
the underlying value for the attribute, using a delta that varies over
the course of the simple duration, starting from a delta of 0 and ending
with the delta specified with the by attribute." (SMILANIM 3.2.2)
Therefore it might seem like by-animation of by="1" means to ADD to the
underlying scale factor. Furthermore, the underlying scale factor when
not otherwise specified might seemt to be 1, but the SVG WG have decided
it's 0. This is inconsistent with the definition of addition for
animateTransform (post-multiplication of matrices) but it is the
behaviour required by SVGT1.2 test suite and used by Opera.
The following animation should go from 0 to 4, over 2s so at t=1s, the
scale factor should be 2.
-->
<g transform="translate(50 150)">
<use xlink:href="#circle">
<animateTransform attributeName="transform"
type="scale" by="4" dur="2s" fill="freeze"/>
</use>
</g>
<!-- by animation #2 -->
<g transform="translate(150 150)">
<use xlink:href="#circle" transform="scale(4)">
<animateTransform attributeName="transform"
type="scale" by="1" dur="2s" fill="freeze" additive="sum"/>
</use>
</g>
<!-- from-by animation -->
<g transform="translate(250 150)">
<use xlink:href="#circle">
<animateTransform attributeName="transform"
type="scale" from="2" by="0" dur="2s" fill="freeze"/>
</use>
</g>
<!-- values animation -->
<g transform="translate(50 250)">
<use xlink:href="#circle">
<animateTransform attributeName="transform"
type="scale" values="0; 10; 2; 5; -1" dur="2s" fill="freeze"/>
</use>
</g>
<!-- repetition -->
<g transform="translate(150 250)">
<use xlink:href="#circle">
<animateTransform attributeName="transform" type="scale" from="0"
to="0.6" dur="0.3s" repeatCount="4" accumulate="sum"
fill="freeze"/>
</use>
</g>
<!-- repeated to-animation (should NOT accumulate) -->
<g transform="translate(250 250)">
<use xlink:href="#circle">
<animateTransform attributeName="transform" type="scale"
to="6" dur="0.75" repeatCount="2" accumulate="sum"
fill="freeze"/>
</use>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@ -0,0 +1,43 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<g id="smiley">
<circle fill="yellow" stroke="black" stroke-width="2" cx="0" cy="0"
r="40"/>
<circle fill="white" stroke="black" stroke-width="1" cx="-14" cy="-14"
r="14"/>
<circle fill="white" stroke="black" stroke-width="1" cx="14" cy="-14"
r="14"/>
<circle cx="-10" cy="-14" r="4"/>
<circle cx="10" cy="-14" r="4"/>
<path d="m-11 14a13,13 0 0,0 22,0" fill="none" stroke="black"/>
</g>
</defs>
<g transform="translate(50 50)">
<use xlink:href="#smiley" transform="skewX(30)"/>
</g>
<g transform="translate(150 50)">
<use xlink:href="#smiley" transform="skewX(30)"/>
</g>
<g transform="translate(250 50)">
<use xlink:href="#smiley" transform="skewX(30)"/>
</g>
<g transform="translate(50 150)">
<use xlink:href="#smiley" transform="skewX(30)"/>
</g>
<g transform="translate(150 150)">
<use xlink:href="#smiley" transform="skewX(30)"/>
</g>
<g transform="translate(250 150)">
<use xlink:href="#smiley" transform="skewX(30)"/>
</g>
<g transform="translate(50 250)">
<use xlink:href="#smiley" transform="skewX(30)"/>
</g>
<g transform="translate(150 250)">
<use xlink:href="#smiley" transform="skewX(30)"/>
</g>
<g transform="translate(250 250)">
<use xlink:href="#smiley" transform="skewX(30)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,86 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="setTimeAndSnapshot(1, true)">
<script xlink:href="../smil-util.js" type="text/javascript"/>
<defs>
<g id="smiley">
<circle fill="yellow" stroke="black" stroke-width="2" cx="0" cy="0"
r="40"/>
<circle fill="white" stroke="black" stroke-width="1" cx="-14" cy="-14"
r="14"/>
<circle fill="white" stroke="black" stroke-width="1" cx="14" cy="-14"
r="14"/>
<circle cx="-10" cy="-14" r="4"/>
<circle cx="10" cy="-14" r="4"/>
<path d="m-11 14a13,13 0 0,0 22,0" fill="none" stroke="black"/>
</g>
</defs>
<!-- from-to animation -->
<g transform="translate(50 50)">
<use xlink:href="#smiley">
<animateTransform attributeName="transform" attributeType="XML"
type="skewX" fill="freeze" from="-30" to="90" dur="2s"/>
</use>
</g>
<!-- from-by animation -->
<g transform="translate(150 50)">
<use xlink:href="#smiley">
<animateTransform attributeName="transform" attributeType="XML"
type="skewX" fill="freeze" from="60" by="-60" dur="2s"/>
</use>
</g>
<!-- by animation -->
<g transform="translate(250 50) skewX(-15)">
<use xlink:href="#smiley" transform="skewX(15)">
<animateTransform attributeName="transform" attributeType="XML"
type="skewX" fill="freeze" by="60" dur="2s"/>
</use>
</g>
<!-- to animation -->
<g transform="translate(50 150)">
<use xlink:href="#smiley" transform="skewX(15)">
<animateTransform attributeName="transform" attributeType="XML"
type="skewX" fill="freeze" to="45" dur="2s"/>
</use>
</g>
<!-- values animation -->
<g transform="translate(150 150)">
<use xlink:href="#smiley">
<animateTransform attributeName="transform" attributeType="XML"
type="skewX" fill="freeze" values="10; 40; 20; 60" dur="2s"/>
</use>
</g>
<!-- additive -->
<g transform="translate(250 150)">
<use xlink:href="#smiley" transform="skewY(-30)">
<animateTransform attributeName="transform" attributeType="XML"
type="skewY" fill="freeze" to="30" dur="2s"/>
<animateTransform attributeName="transform" attributeType="XML"
type="skewX" fill="freeze" from="-30" to="90" dur="2s" additive="sum"/>
</use>
</g>
<!-- accumulate: none -->
<g transform="translate(50 250)">
<use xlink:href="#smiley">
<animateTransform attributeName="transform" attributeType="XML"
type="skewX" fill="freeze" from="20" to="50" dur="0.75s"
repeatCount="3"/>
</use>
</g>
<!-- accumulate: sum -->
<g transform="translate(150 250)">
<use xlink:href="#smiley">
<animateTransform attributeName="transform" attributeType="XML"
type="skewX" fill="freeze" from="0" to="22.5" dur="0.75"
accumulate="sum" repeatCount="3"/>
</use>
</g>
<!-- angles > 360 -->
<g transform="translate(250 250)">
<use xlink:href="#smiley">
<animateTransform attributeName="transform" attributeType="XML"
type="skewX" fill="freeze" from="-690" to="750" dur="2s"/>
</use>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB