Bug 540588. Add support for SMIL animation of <integer> attributes in SVG. r=dholbert

This commit is contained in:
Jonathan Watt 2010-02-18 21:51:00 +00:00
parent 232dae9b42
commit f2e0136d80
13 changed files with 798 additions and 9 deletions

View File

@ -72,6 +72,7 @@ CPPSRCS += \
nsSMILValue.cpp \
SMILBoolType.cpp \
SMILEnumType.cpp \
SMILIntegerType.cpp \
$(NULL)
endif

View File

@ -0,0 +1,123 @@
/* -*- 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 the Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* 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 "SMILIntegerType.h"
#include "nsSMILValue.h"
#include "nsDebug.h"
#include <math.h>
namespace mozilla {
/*static*/ SMILIntegerType SMILIntegerType::sSingleton;
nsresult
SMILIntegerType::Init(nsSMILValue& aValue) const
{
NS_ABORT_IF_FALSE(aValue.IsNull(), "Unexpected value type");
aValue.mU.mInt = 0;
aValue.mType = this;
return NS_OK;
}
void
SMILIntegerType::Destroy(nsSMILValue& aValue) const
{
NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value");
aValue.mU.mInt = 0;
aValue.mType = &nsSMILNullType::sSingleton;
}
nsresult
SMILIntegerType::Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const
{
NS_PRECONDITION(aDest.mType == aSrc.mType, "Incompatible SMIL types");
NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL value");
aDest.mU.mInt = aSrc.mU.mInt;
return NS_OK;
}
nsresult
SMILIntegerType::Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
PRUint32 aCount) const
{
NS_PRECONDITION(aValueToAdd.mType == aDest.mType,
"Trying to add invalid types");
NS_PRECONDITION(aValueToAdd.mType == this, "Unexpected source type");
aDest.mU.mInt += aValueToAdd.mU.mInt * aCount;
return NS_OK;
}
nsresult
SMILIntegerType::ComputeDistance(const nsSMILValue& aFrom,
const nsSMILValue& aTo,
double& aDistance) const
{
NS_PRECONDITION(aFrom.mType == aTo.mType,"Trying to compare different types");
NS_PRECONDITION(aFrom.mType == this, "Unexpected source type");
aDistance = fabs(double(aTo.mU.mInt - aFrom.mU.mInt));
return NS_OK;
}
nsresult
SMILIntegerType::Interpolate(const nsSMILValue& aStartVal,
const nsSMILValue& aEndVal,
double aUnitDistance,
nsSMILValue& aResult) const
{
NS_PRECONDITION(aStartVal.mType == aEndVal.mType,
"Trying to interpolate different types");
NS_PRECONDITION(aStartVal.mType == this,
"Unexpected types for interpolation");
NS_PRECONDITION(aResult.mType == this, "Unexpected result type");
const double startVal = double(aStartVal.mU.mInt);
const double endVal = double(aEndVal.mU.mInt);
const double currentVal = startVal + (endVal - startVal) * aUnitDistance;
// When currentVal is exactly midway between its two nearest integers, we
// jump to the "next" integer to provide simple, easy to remember and
// consistent behaviour (from the SMIL author's point of view).
if (startVal < endVal) {
aResult.mU.mInt = PRInt64(floor(currentVal + 0.5)); // round mid up
} else {
aResult.mU.mInt = PRInt64(ceil(currentVal - 0.5)); // round mid down
}
return NS_OK;
}
} // namespace mozilla

View File

@ -0,0 +1,68 @@
/* -*- 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 the Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* 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_SMILINTEGERTYPE_H_
#define MOZILLA_SMILINTEGERTYPE_H_
#include "nsISMILType.h"
namespace mozilla {
class SMILIntegerType : public nsISMILType
{
public:
virtual nsresult Init(nsSMILValue& aValue) const;
virtual void Destroy(nsSMILValue&) const;
virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
virtual nsresult Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
PRUint32 aCount) 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;
static SMILIntegerType sSingleton;
private:
SMILIntegerType() {}
};
} // namespace mozilla
#endif // MOZILLA_SMILINTEGERTYPE_H_

View File

@ -1336,6 +1336,19 @@ nsSVGElement::DidChangeInteger(PRUint8 aAttrEnum, PRBool aDoSetAttr)
newStr, PR_TRUE);
}
void
nsSVGElement::DidAnimateInteger(PRUint8 aAttrEnum)
{
nsIFrame* frame = GetPrimaryFrame();
if (frame) {
IntegerAttributesInfo info = GetIntegerInfo();
frame->AttributeChanged(kNameSpaceID_None,
*info.mIntegerInfo[aAttrEnum].mName,
nsIDOMMutationEvent::MODIFICATION);
}
}
void
nsSVGElement::GetAnimatedIntegerValues(PRInt32 *aFirst, ...)
{
@ -1351,7 +1364,7 @@ nsSVGElement::GetAnimatedIntegerValues(PRInt32 *aFirst, ...)
va_start(args, aFirst);
while (n && i < info.mIntegerCount) {
*n = info.mIntegers[i++].GetAnimValue();
*n = info.mIntegers[i++].GetAnimValue(this);
n = va_arg(args, PRInt32*);
}
va_end(args);
@ -1766,6 +1779,16 @@ nsSVGElement::GetAnimatedAttr(const nsIAtom* aName)
}
}
// Integers:
{
IntegerAttributesInfo info = GetIntegerInfo();
for (PRUint32 i = 0; i < info.mIntegerCount; i++) {
if (aName == *info.mIntegerInfo[i].mName) {
return info.mIntegers[i].ToSMILAttr(this);
}
}
}
// Enumerations:
{
EnumAttributesInfo info = GetEnumInfo();

View File

@ -157,6 +157,7 @@ public:
virtual void DidAnimateLength(PRUint8 aAttrEnum);
virtual void DidAnimateNumber(PRUint8 aAttrEnum);
virtual void DidAnimateInteger(PRUint8 aAttrEnum);
virtual void DidAnimateAngle(PRUint8 aAttrEnum);
virtual void DidAnimateBoolean(PRUint8 aAttrEnum);
virtual void DidAnimateEnum(PRUint8 aAttrEnum);

View File

@ -323,6 +323,12 @@ nsSVGFE::DidAnimateNumber(PRUint8 aAttrEnum)
DidAnimateAttr(this);
}
void
nsSVGFE::DidAnimateInteger(PRUint8 aAttrEnum)
{
DidAnimateAttr(this);
}
void
nsSVGFE::DidAnimateEnum(PRUint8 aAttrEnum)
{
@ -3203,7 +3209,7 @@ nsSVGFETurbulenceElement::Filter(nsSVGFilterInstance *instance,
#endif
float fX, fY, seed;
PRInt32 octaves = mIntegerAttributes[OCTAVES].GetAnimValue();
PRInt32 octaves = mIntegerAttributes[OCTAVES].GetAnimValue(this);
PRUint16 type = mEnumAttributes[TYPE].GetAnimValue(this);
PRUint16 stitch = mEnumAttributes[STITCHTILES].GetAnimValue(this);

View File

@ -219,6 +219,7 @@ protected:
virtual LengthAttributesInfo GetLengthInfo();
virtual void DidAnimateLength(PRUint8 aAttrEnum);
virtual void DidAnimateNumber(PRUint8 aAttrEnum);
virtual void DidAnimateInteger(PRUint8 aAttrEnum);
virtual void DidAnimateEnum(PRUint8 aAttrEnum);
virtual void DidAnimateBoolean(PRUint8 aAttrEnum);
virtual void DidAnimatePreserveAspectRatio();

View File

@ -35,7 +35,12 @@
* ***** END LICENSE BLOCK ***** */
#include "nsSVGInteger.h"
#ifdef MOZ_SMIL
#include "nsSMILValue.h"
#include "SMILIntegerType.h"
#endif // MOZ_SMIL
using namespace mozilla;
NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGInteger::DOMAnimatedInteger, mSVGElement)
@ -67,7 +72,14 @@ nsSVGInteger::SetBaseValueString(const nsAString &aValueAsString,
return NS_ERROR_DOM_SYNTAX_ERR;
}
mBaseVal = mAnimVal = val;
if (val != mBaseVal) {
mBaseVal = mAnimVal = val;
#ifdef MOZ_SMIL
if (mIsAnimated) {
aSVGElement->AnimationNeedsResample();
}
#endif
}
return NS_OK;
}
@ -84,8 +96,23 @@ nsSVGInteger::SetBaseValue(int aValue,
nsSVGElement *aSVGElement,
PRBool aDoSetAttr)
{
mAnimVal = mBaseVal = aValue;
aSVGElement->DidChangeInteger(mAttrEnum, aDoSetAttr);
if (aValue != mBaseVal) {
mBaseVal = mAnimVal = aValue;
aSVGElement->DidChangeInteger(mAttrEnum, aDoSetAttr);
#ifdef MOZ_SMIL
if (mIsAnimated) {
aSVGElement->AnimationNeedsResample();
}
#endif
}
}
void
nsSVGInteger::SetAnimValue(int aValue, nsSVGElement *aSVGElement)
{
mAnimVal = aValue;
mIsAnimated = PR_TRUE;
aSVGElement->DidAnimateInteger(mAttrEnum);
}
nsresult
@ -99,3 +126,62 @@ nsSVGInteger::ToDOMAnimatedInteger(nsIDOMSVGAnimatedInteger **aResult,
NS_ADDREF(*aResult);
return NS_OK;
}
#ifdef MOZ_SMIL
nsISMILAttr*
nsSVGInteger::ToSMILAttr(nsSVGElement *aSVGElement)
{
return new SMILInteger(this, aSVGElement);
}
nsresult
nsSVGInteger::SMILInteger::ValueFromString(const nsAString& aStr,
const nsISMILAnimationElement* /*aSrcElement*/,
nsSMILValue& aValue) const
{
NS_ConvertUTF16toUTF8 value(aStr);
const char *str = value.get();
if (NS_IsAsciiWhitespace(*str))
return NS_ERROR_FAILURE;
char *rest;
PRInt32 val = strtol(str, &rest, 10);
if (rest == str || *rest != '\0') {
return NS_ERROR_FAILURE;
}
nsSMILValue smilVal(&SMILIntegerType::sSingleton);
smilVal.mU.mInt = val;
aValue = smilVal;
return NS_OK;
}
nsSMILValue
nsSVGInteger::SMILInteger::GetBaseValue() const
{
nsSMILValue val(&SMILIntegerType::sSingleton);
val.mU.mInt = mVal->mBaseVal;
return val;
}
void
nsSVGInteger::SMILInteger::ClearAnimValue()
{
if (mVal->mIsAnimated) {
mVal->SetAnimValue(mVal->mBaseVal, mSVGElement);
mVal->mIsAnimated = PR_FALSE;
}
}
nsresult
nsSVGInteger::SMILInteger::SetAnimValue(const nsSMILValue& aValue)
{
NS_ASSERTION(aValue.mType == &SMILIntegerType::sSingleton,
"Unexpected type to assign animated value");
if (aValue.mType == &SMILIntegerType::sSingleton) {
mVal->SetAnimValue(int(aValue.mU.mInt), mSVGElement);
}
return NS_OK;
}
#endif // MOZ_SMIL

View File

@ -48,6 +48,7 @@ public:
void Init(PRUint8 aAttrEnum = 0xff, PRInt32 aValue = 0) {
mAnimVal = mBaseVal = aValue;
mAttrEnum = aAttrEnum;
mIsAnimated = PR_FALSE;
}
nsresult SetBaseValueString(const nsAString& aValue,
@ -58,17 +59,29 @@ public:
void SetBaseValue(PRInt32 aValue, nsSVGElement *aSVGElement, PRBool aDoSetAttr);
PRInt32 GetBaseValue() const
{ return mBaseVal; }
PRInt32 GetAnimValue() const
{ return mAnimVal; }
void SetAnimValue(int aValue, nsSVGElement *aSVGElement);
int GetAnimValue(nsSVGElement *aSVGElement) const
{
#ifdef MOZ_SMIL
aSVGElement->FlushAnimations();
#endif
return mAnimVal;
}
nsresult ToDOMAnimatedInteger(nsIDOMSVGAnimatedInteger **aResult,
nsSVGElement* aSVGElement);
#ifdef MOZ_SMIL
// Returns a new nsISMILAttr object that the caller must delete
nsISMILAttr* ToSMILAttr(nsSVGElement* aSVGElement);
#endif // MOZ_SMIL
private:
PRInt32 mAnimVal;
PRInt32 mBaseVal;
PRUint8 mAttrEnum; // element specified tracking for attribute
PRPackedBool mIsAnimated;
struct DOMAnimatedInteger : public nsIDOMSVGAnimatedInteger
{
@ -86,9 +99,32 @@ private:
NS_IMETHOD SetBaseVal(PRInt32 aValue)
{ mVal->SetBaseValue(aValue, mSVGElement, PR_TRUE); return NS_OK; }
NS_IMETHOD GetAnimVal(PRInt32* aResult)
{ *aResult = mVal->GetAnimValue(); return NS_OK; }
{ *aResult = mVal->GetAnimValue(mSVGElement); return NS_OK; }
};
#ifdef MOZ_SMIL
struct SMILInteger : public nsISMILAttr
{
public:
SMILInteger(nsSVGInteger* aVal, nsSVGElement* aSVGElement)
: mVal(aVal), mSVGElement(aSVGElement) {}
// 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.
nsSVGInteger* mVal;
nsSVGElement* mSVGElement;
// nsISMILAttr methods
virtual nsresult ValueFromString(const nsAString& aStr,
const nsISMILAnimationElement* aSrcElement,
nsSMILValue& aValue) const;
virtual nsSMILValue GetBaseValue() const;
virtual void ClearAnimValue();
virtual nsresult SetAnimValue(const nsSMILValue& aValue);
};
#endif // MOZ_SMIL
};
#endif //__NS_SVGINTEGER_H__

View File

@ -0,0 +1,26 @@
<svg xmlns="http://www.w3.org/2000/svg">
<filter id="filter_1" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="1"/>
</filter>
<filter id="filter_2" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="2"/>
</filter>
<filter id="filter_3" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="3"/>
</filter>
<filter id="filter_4" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="4"/>
</filter>
<rect x="0" y="0" width="20" height="20" filter="url(#filter_3)"/>
<rect x="20" y="0" width="20" height="20" filter="url(#filter_4)"/>
<rect x="0" y="20" width="20" height="20" filter="url(#filter_2)"/>
<rect x="20" y="20" width="20" height="20" filter="url(#filter_1)"/>
<rect x="0" y="40" width="20" height="20" filter="url(#filter_3)"/>
<rect x="20" y="40" width="20" height="20" filter="url(#filter_4)"/>
<rect x="0" y="60" width="20" height="20" filter="url(#filter_2)"/>
<rect x="20" y="60" width="20" height="20" filter="url(#filter_1)"/>
<rect x="0" y="80" width="20" height="20" filter="url(#filter_1)"/>
<rect x="20" y="80" width="20" height="20" filter="url(#filter_4)"/>
<rect x="0" y="100" width="20" height="20" filter="url(#filter_4)"/>
<rect x="20" y="100" width="20" height="20" filter="url(#filter_1)"/>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,213 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="setTimeAndSnapshot(5, true)">
<title>Test animation of the "numOctaves" &lt;integer&gt; attribute on the "feTurbulence" element</title>
<script xlink:href="smil-util.js" type="text/javascript"/>
<!-- Our implementation strategy for animating integers with
calcMode="linear" is to use round(), with the slight twist that we
round "to the NEXT value" when the current time puts us exactly midway
between two integer values. (This is so that the result of midpoint
rounding does not depend on whether we're animating up to a higher
value or animating down to a lower value.) Note that one of the quirks
of using round() is that the start and end values of any integer
range only receive half as much time as any intermediary values. This
is as you would expect mathematically, but it's probably unexpected
for most users!
We could try to avoid this round() quirk by coming up with a better
implementation strategy for calcMode="linear", but animation of the
few integer attributes in SVG 1.1 is extremely unlikely (so this
issue is very low priority), and it's actually difficult to find a
better strategy that doesn't have its own undesirable quirks.
One alternative could be to divide the time evenly amoungst each
integer. (I.e. it would be similar to calcMode="discrete", except it
would also visit all the intermediary values, not just the start and
end values). The issue with this approach is that for a simple "to"
animation the animation wouldn't actually seem to change anything until
interpolation reaches the second integer value. This could be avoided
by skipping the initial value and distributing the time between the
other values, but then in the case of a "from-to" animation where the
from value is different to the underlying attribute value, the
animation would seem to skip the first value. Not that the same sort of
problem exists at the other end of the simple duration, where it will
reach the final integer value before the end of the simple duration.
This could be avoided by only setting the final value right at the end
of the simple duration and distributing the time between evenly
between the other values, but then the final value will only be seen if
fill="freeze".
There are many other problems with other implementation strategies. The
more you think about them, add the complexity of 'values', 'by' etc,
and think of cases where they behave strangely (e.g. animating between
just two adjacent integers, up or down, etc.), the more ugly it gets.
It's really not worth it for SVG 1.1. Maybe if you could use SMIL for
'font-size' or something even more likely to be animated it would be.
-->
<!-- Some calcMode="linear" tests animating *up* to higer values. -->
<!-- At 5s the animated value should be 3. -->
<filter id="filter_1" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="1">
<animate attributeName="numOctaves"
calcMode="linear"
begin="0s" dur="6.1s"
to="4"
fill="freeze"/>
</feTurbulence>
</filter>
<rect x="0" width="20" height="20" filter="url(#filter_1)"/>
<!-- At exactly 5s the animated value should change to 4. -->
<filter id="filter_2" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="1">
<animate attributeName="numOctaves"
calcMode="linear"
begin="0s" dur="6s"
to="4"
fill="freeze"/>
</feTurbulence>
</filter>
<rect x="20" width="20" height="20" filter="url(#filter_2)"/>
<!-- Some calcMode="linear" tests animating *down* to lower values. -->
<!-- At 5s the animated value should be 2. -->
<filter id="filter_3" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="4">
<animate attributeName="numOctaves"
calcMode="linear"
begin="0s" dur="6.1s"
to="1"
fill="freeze"/>
</feTurbulence>
</filter>
<rect x="0" y="20" width="20" height="20" filter="url(#filter_3)"/>
<!-- At exactly 5s the animated value should change to 1. -->
<filter id="filter_4" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="4">
<animate attributeName="numOctaves"
calcMode="linear"
begin="0s" dur="6s"
to="1"
fill="freeze"/>
</feTurbulence>
</filter>
<rect x="20" y="20" width="20" height="20" filter="url(#filter_4)"/>
<!-- Some 'by' animation tests -->
<!-- At 5s the animated value should be 3. -->
<filter id="filter_5" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="1">
<animate attributeName="numOctaves"
calcMode="linear"
begin="0s" dur="6.1s"
by="3"
fill="freeze"/>
</feTurbulence>
</filter>
<rect y="40" width="20" height="20" filter="url(#filter_5)"/>
<!-- At exactly 5s the animated value should change to 4. -->
<filter id="filter_6" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="1">
<animate attributeName="numOctaves"
calcMode="linear"
begin="0s" dur="6s"
by="3"
fill="freeze"/>
</feTurbulence>
</filter>
<rect x="20" y="40" width="20" height="20" filter="url(#filter_6)"/>
<!-- calcMode="paced" tests -->
<!-- At 5s the animated value should be 2. -->
<filter id="filter_7" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="4">
<animate attributeName="numOctaves"
calcMode="paced"
begin="0s" dur="6.1s"
values="4; 3; 1"
fill="freeze"/>
</feTurbulence>
</filter>
<rect y="60" width="20" height="20" filter="url(#filter_7)"/>
<!-- At exactly 5s the animated value should change to 1. -->
<filter id="filter_8" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="4">
<animate attributeName="numOctaves"
calcMode="paced"
begin="0s" dur="6s"
values="4; 3; 1"
fill="freeze"/>
</feTurbulence>
</filter>
<rect x="20" y="60" width="20" height="20" filter="url(#filter_8)"/>
<!-- Some calcMode="discrete" tests animating *up* to higer values. -->
<!-- At 5s the animated value should be 1. -->
<filter id="filter_9" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="1">
<animate attributeName="numOctaves"
calcMode="discrete"
begin="0s" dur="10.1s"
to="4"
fill="freeze"/>
</feTurbulence>
</filter>
<rect x="0" y="80" width="20" height="20" filter="url(#filter_9)"/>
<!-- At exactly 5s the animated value should change to 4. -->
<filter id="filter_10" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="1">
<animate attributeName="numOctaves"
calcMode="discrete"
begin="0s" dur="10s"
to="4"
fill="freeze"/>
</feTurbulence>
</filter>
<rect x="20" y="80" width="20" height="20" filter="url(#filter_10)"/>
<!-- Some calcMode="discrete" tests animating *down* to lower values. -->
<!-- At 5s the animated value should be 4. -->
<filter id="filter_11" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="4">
<animate attributeName="numOctaves"
calcMode="discrete"
begin="0s" dur="10.1s"
to="1"
fill="freeze"/>
</feTurbulence>
</filter>
<rect x="0" y="100" width="20" height="20" filter="url(#filter_11)"/>
<!-- At exactly 5s the animated value should change to 1. -->
<filter id="filter_12" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="4">
<animate attributeName="numOctaves"
calcMode="discrete"
begin="0s" dur="10s"
to="1"
fill="freeze"/>
</feTurbulence>
</filter>
<rect x="20" y="100" width="20" height="20" filter="url(#filter_12)"/>
</svg>

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

@ -0,0 +1,202 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="setTimeAndSnapshot(3, true)">
<title>Test animation of the "numOctaves" &lt;integer&gt; attribute on the "feTurbulence" element</title>
<script xlink:href="smil-util.js" type="text/javascript"/>
<!-- This is an unfinished and unused testcase that would not pass given the
current implementation strategy. This testcase assumes that the
strategy should be to give each value an equal slice of the simple
duration. In other words if animating from 1 to 4 in 4 seconds, then
each of the values 1, 2, 3 and 4 would get 1 second each.
See the comment in anim-feTurbulence-numOctaves-01.svg for more on
implementation strategy.
-->
<!-- Animation of integers is actually more complicated than lengths. It's
necessary to "jump" from value to value since you're dealing with
discrete integers rather than continuous real numbers.
The spec doesn't say exactly how to behave, but we assume that the each
of the values in a from-to animation gets an equal slice of the simple
duration. We also assume that at times that are exactly midway between
two integers, we should jump to the "next" integer. In other words, when
animating from 0 to 1 in 1 second, at 0.5 seconds the value changes to
1; but when animating from 1 to 0 in 1 second, at 0.5 seconds the value
changes to 0. This is different from floor(), round() or ceil()
behavior, and we test that by animating both "up" and "down" below.
-->
<!-- Some tests animating *up* to higer values. -->
<!-- Each of the four values should get an equal slice of the duration -
that is 3.25s - so at 3s the animated value should still be 1. -->
<filter id="filter_1" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="1">
<animate attributeName="numOctaves"
calcMode="linear"
begin="0s" dur="13s"
to="4"
fill="freeze"/>
</feTurbulence>
</filter>
<rect width="20" height="20" filter="url(#filter_1)"/>
<!-- Each of the four values should get an equal slice of the duration -
that is 3s - so at exactly 3s the animated value should become 2. -->
<filter id="filter_2" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="1">
<animate attributeName="numOctaves"
calcMode="linear"
begin="0s" dur="12s"
to="4"
fill="freeze"/>
</feTurbulence>
</filter>
<rect x="20" width="20" height="20" filter="url(#filter_2)"/>
<!-- Each of the four values should get an equal slice of the duration -
that is 1.25s - so at 3s the animated value should still be 3. -->
<filter id="filter_3" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="1">
<animate attributeName="numOctaves"
calcMode="linear"
begin="0s" dur="5s"
to="4"
fill="freeze"/>
</feTurbulence>
</filter>
<rect x="40" width="20" height="20" filter="url(#filter_3)"/>
<!-- Each of the four values should get an equal slice of the duration -
that is 1s - so at exactly 3s the animated value should become 4. -->
<filter id="filter_4" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="1">
<animate attributeName="numOctaves"
calcMode="linear"
begin="0s" dur="4s"
to="4"
fill="freeze"/>
</feTurbulence>
</filter>
<rect x="60" width="20" height="20" filter="url(#filter_4)"/>
<!-- Some tests animating *down* to lower values. -->
<!-- Each of the four values should get an equal slice of the duration -
that is 3.25s - so at 3s the animated value should still be 4. -->
<filter id="filter_5" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="4">
<animate attributeName="numOctaves"
calcMode="linear"
begin="0s" dur="13s"
to="1"
fill="freeze"/>
</feTurbulence>
</filter>
<rect y="20" width="20" height="20" filter="url(#filter_5)"/>
<!-- Each of the four values should get an equal slice of the duration -
that is 3s - so at exactly 3s the animated value should become 3. -->
<filter id="filter_6" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="4">
<animate attributeName="numOctaves"
calcMode="linear"
begin="0s" dur="12s"
to="1"
fill="freeze"/>
</feTurbulence>
</filter>
<rect x="20" y="20" width="20" height="20" filter="url(#filter_6)"/>
<!-- Each of the four values should get an equal slice of the duration -
that is 1.25s - so at 3s the animated value should still be 2. -->
<filter id="filter_7" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="4">
<animate attributeName="numOctaves"
calcMode="linear"
begin="0s" dur="5s"
to="1"
fill="freeze"/>
</feTurbulence>
</filter>
<rect x="40" y="20" width="20" height="20" filter="url(#filter_7)"/>
<!-- Each of the four values should get an equal slice of the duration -
that is 1s - so at exactly 3s the animated value should become 1. -->
<filter id="filter_8" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="4">
<animate attributeName="numOctaves"
calcMode="linear"
begin="0s" dur="4s"
to="1"
fill="freeze"/>
</feTurbulence>
</filter>
<rect x="60" y="20" width="20" height="20" filter="url(#filter_8)"/>
<!-- Some 'by' animation tests -->
<!-- Each of the four values should get an equal slice of the duration -
that is 1.25s - so at 3s the animated value should still be 3. -->
<filter id="filter_9" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="1">
<animate attributeName="numOctaves"
calcMode="linear"
begin="0s" dur="5s"
by="3"
fill="freeze"/>
</feTurbulence>
</filter>
<rect y="40" width="20" height="20" filter="url(#filter_9)"/>
<!-- Each of the four values should get an equal slice of the duration -
that is 1s - so at exactly 3s the animated value should become 4. -->
<filter id="filter_10" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="1">
<animate attributeName="numOctaves"
calcMode="linear"
begin="0s" dur="4s"
by="3"
fill="freeze"/>
</feTurbulence>
</filter>
<rect x="20" y="40" width="20" height="20" filter="url(#filter_10)"/>
<!-- calcMode="paced" tests -->
<!-- Each of the four values should get an equal slice of the duration -
that is 1.25s - so at 3s the animated value should still be 2. -->
<filter id="filter_11" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="4">
<animate attributeName="numOctaves"
calcMode="paced"
begin="0s" dur="5s"
values="4; 3; 1"
fill="freeze"/>
</feTurbulence>
</filter>
<rect y="60" width="20" height="20" filter="url(#filter_11)"/>
<!-- Each of the four values should get an equal slice of the duration -
that is 1s - so at exactly 3s the animated value should become 1. -->
<filter id="filter_12" x="0%" y="0%" width="100%" height="100%">
<feTurbulence type="turbulence" baseFrequency="0.01" numOctaves="4">
<animate attributeName="numOctaves"
calcMode="paced"
begin="0s" dur="4s"
values="4; 3; 1"
fill="freeze"/>
</feTurbulence>
</filter>
<rect x="20" y="60" width="20" height="20" filter="url(#filter_12)"/>
</svg>

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@ -81,6 +81,9 @@ fails == anim-fillopacity-1xml.svg anim-standard-ref.svg # bug 534028
== anim-offset-01.svg lime.svg
== anim-pathLength-01.svg anim-pathLength-01-ref.svg
# animate some <integer> attributes:
== anim-feTurbulence-numOctaves-01.svg anim-feTurbulence-numOctaves-01-ref.svg
# animate some <angle> attributes:
== anim-marker-orient-01.svg lime.svg