Bug 540479. Add support for SMIL animation of boolean attributes in SVG. r=dholbert

This commit is contained in:
Jonathan Watt 2010-01-24 16:42:08 +00:00
Родитель c215683685
Коммит 73a3d22d30
12 изменённых файлов: 374 добавлений и 7 удалений

Просмотреть файл

@ -70,6 +70,7 @@ CPPSRCS += \
nsSMILTimeValue.cpp \
nsSMILTimeValueSpec.cpp \
nsSMILValue.cpp \
SMILBoolType.cpp \
SMILEnumType.cpp \
$(NULL)
endif

Просмотреть файл

@ -0,0 +1,107 @@
/* -*- 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 "SMILBoolType.h"
#include "nsSMILValue.h"
#include "nsDebug.h"
#include <math.h>
namespace mozilla {
/*static*/ SMILBoolType SMILBoolType::sSingleton;
nsresult
SMILBoolType::Init(nsSMILValue& aValue) const
{
NS_PRECONDITION(aValue.mType == this || aValue.IsNull(),
"Unexpected value type");
aValue.mU.mBool = PR_FALSE;
aValue.mType = this;
return NS_OK;
}
void
SMILBoolType::Destroy(nsSMILValue& aValue) const
{
NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value.");
aValue.mU.mBool = PR_FALSE;
aValue.mType = &nsSMILNullType::sSingleton;
}
nsresult
SMILBoolType::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.mBool = aSrc.mU.mBool;
return NS_OK;
}
nsresult
SMILBoolType::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");
return NS_ERROR_FAILURE; // bool values can't be added to each other
}
nsresult
SMILBoolType::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");
return NS_ERROR_FAILURE; // there is no concept of distance between bool values
}
nsresult
SMILBoolType::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.");
return NS_ERROR_FAILURE; // bool values do not interpolate
}
} // namespace mozilla

Просмотреть файл

@ -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_SMILBOOLTYPE_H_
#define MOZILLA_SMILBOOLTYPE_H_
#include "nsISMILType.h"
namespace mozilla {
class SMILBoolType : 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 SMILBoolType sSingleton;
private:
SMILBoolType() {}
};
} // namespace mozilla
#endif // MOZILLA_SMILBOOLTYPE_H_

Просмотреть файл

@ -69,6 +69,7 @@ public:
nsSMILValue& aResult) const;
union {
PRBool mBool;
PRUint64 mUint;
PRInt64 mInt;
double mDouble;

Просмотреть файл

@ -35,6 +35,12 @@
* ***** END LICENSE BLOCK ***** */
#include "nsSVGBoolean.h"
#ifdef MOZ_SMIL
#include "nsSMILValue.h"
#include "SMILBoolType.h"
#endif // MOZ_SMIL
using namespace mozilla;
NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGBoolean::DOMAnimatedBoolean, mSVGElement)
@ -64,6 +70,11 @@ nsSVGBoolean::SetBaseValueString(const nsAString &aValueAsString,
return NS_ERROR_DOM_SYNTAX_ERR;
mBaseVal = mAnimVal = val;
#ifdef MOZ_SMIL
if (mIsAnimated) {
aSVGElement->AnimationNeedsResample();
}
#endif
return NS_OK;
}
@ -81,8 +92,23 @@ nsSVGBoolean::SetBaseValue(PRBool aValue,
{
NS_PRECONDITION(aValue == PR_TRUE || aValue == PR_FALSE, "Boolean out of range");
mAnimVal = mBaseVal = aValue;
aSVGElement->DidChangeBoolean(mAttrEnum, PR_TRUE);
if (aValue != mBaseVal) {
mAnimVal = mBaseVal = aValue;
aSVGElement->DidChangeBoolean(mAttrEnum, PR_TRUE);
#ifdef MOZ_SMIL
if (mIsAnimated) {
aSVGElement->AnimationNeedsResample();
}
#endif
}
}
void
nsSVGBoolean::SetAnimValue(PRBool aValue, nsSVGElement *aSVGElement)
{
mAnimVal = aValue;
mIsAnimated = PR_TRUE;
aSVGElement->DidAnimateBoolean(mAttrEnum);
}
nsresult
@ -96,3 +122,57 @@ nsSVGBoolean::ToDOMAnimatedBoolean(nsIDOMSVGAnimatedBoolean **aResult,
NS_ADDREF(*aResult);
return NS_OK;
}
#ifdef MOZ_SMIL
nsISMILAttr*
nsSVGBoolean::ToSMILAttr(nsSVGElement *aSVGElement)
{
return new SMILBool(this, aSVGElement);
}
nsresult
nsSVGBoolean::SMILBool::ValueFromString(const nsAString& aStr,
const nsISMILAnimationElement* /*aSrcElement*/,
nsSMILValue& aValue) const
{
nsSMILValue val(&SMILBoolType::sSingleton);
if (aStr.EqualsLiteral("true"))
val.mU.mBool = PR_TRUE;
else if (aStr.EqualsLiteral("false"))
val.mU.mBool = PR_FALSE;
else
return NS_ERROR_FAILURE;
aValue = val;
return NS_OK;
}
nsSMILValue
nsSVGBoolean::SMILBool::GetBaseValue() const
{
nsSMILValue val(&SMILBoolType::sSingleton);
val.mU.mBool = mVal->mBaseVal;
return val;
}
void
nsSVGBoolean::SMILBool::ClearAnimValue()
{
if (mVal->mIsAnimated) {
mVal->SetAnimValue(mVal->mBaseVal, mSVGElement);
mVal->mIsAnimated = PR_FALSE;
}
}
nsresult
nsSVGBoolean::SMILBool::SetAnimValue(const nsSMILValue& aValue)
{
NS_ASSERTION(aValue.mType == &SMILBoolType::sSingleton,
"Unexpected type to assign animated value");
if (aValue.mType == &SMILBoolType::sSingleton) {
mVal->SetAnimValue(PRUint16(aValue.mU.mBool), mSVGElement);
}
return NS_OK;
}
#endif // MOZ_SMIL

Просмотреть файл

@ -48,6 +48,7 @@ public:
void Init(PRUint8 aAttrEnum = 0xff, PRBool aValue = PR_FALSE) {
mAnimVal = mBaseVal = aValue;
mAttrEnum = aAttrEnum;
mIsAnimated = PR_FALSE;
}
nsresult SetBaseValueString(const nsAString& aValue,
@ -58,16 +59,28 @@ public:
void SetBaseValue(PRBool aValue, nsSVGElement *aSVGElement);
PRBool GetBaseValue() const
{ return mBaseVal; }
PRBool GetAnimValue() const
{ return mAnimVal; }
void SetAnimValue(PRBool aValue, nsSVGElement *aSVGElement);
PRBool GetAnimValue(nsSVGElement *aSVGElement) const
{
#ifdef MOZ_SMIL
aSVGElement->FlushAnimations();
#endif
return mAnimVal;
}
nsresult ToDOMAnimatedBoolean(nsIDOMSVGAnimatedBoolean **aResult,
nsSVGElement* aSVGElement);
#ifdef MOZ_SMIL
// Returns a new nsISMILAttr object that the caller must delete
nsISMILAttr* ToSMILAttr(nsSVGElement* aSVGElement);
#endif // MOZ_SMIL
private:
PRPackedBool mAnimVal;
PRPackedBool mBaseVal;
PRPackedBool mIsAnimated;
PRUint8 mAttrEnum; // element specified tracking for attribute
struct DOMAnimatedBoolean : public nsIDOMSVGAnimatedBoolean
@ -86,9 +99,31 @@ private:
NS_IMETHOD SetBaseVal(PRBool aValue)
{ mVal->SetBaseValue(aValue, mSVGElement); return NS_OK; }
NS_IMETHOD GetAnimVal(PRBool* aResult)
{ *aResult = mVal->GetAnimValue(); return NS_OK; }
{ *aResult = mVal->GetAnimValue(mSVGElement); return NS_OK; }
};
#ifdef MOZ_SMIL
struct SMILBool : public nsISMILAttr
{
public:
SMILBool(nsSVGBoolean* 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.
nsSVGBoolean* 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_SVGBOOLEAN_H__

Просмотреть файл

@ -1422,6 +1422,19 @@ nsSVGElement::DidChangeBoolean(PRUint8 aAttrEnum, PRBool aDoSetAttr)
newStr, PR_TRUE);
}
void
nsSVGElement::DidAnimateBoolean(PRUint8 aAttrEnum)
{
nsIFrame* frame = GetPrimaryFrame();
if (frame) {
BooleanAttributesInfo info = GetBooleanInfo();
frame->AttributeChanged(kNameSpaceID_None,
*info.mBooleanInfo[aAttrEnum].mName,
nsIDOMMutationEvent::MODIFICATION);
}
}
nsSVGElement::EnumAttributesInfo
nsSVGElement::GetEnumInfo()
{
@ -1726,6 +1739,16 @@ nsSVGElement::GetAnimatedAttr(const nsIAtom* aName)
}
}
// Booleans:
{
BooleanAttributesInfo info = GetBooleanInfo();
for (PRUint32 i = 0; i < info.mBooleanCount; i++) {
if (aName == *info.mBooleanInfo[i].mName) {
return info.mBooleans[i].ToSMILAttr(this);
}
}
}
return nsnull;
}

Просмотреть файл

@ -157,6 +157,7 @@ public:
virtual void DidAnimateLength(PRUint8 aAttrEnum);
virtual void DidAnimateNumber(PRUint8 aAttrEnum);
virtual void DidAnimateBoolean(PRUint8 aAttrEnum);
virtual void DidAnimateEnum(PRUint8 aAttrEnum);
void GetAnimatedLengthValues(float *aFirst, ...);

Просмотреть файл

@ -329,6 +329,12 @@ nsSVGFE::DidAnimateEnum(PRUint8 aAttrEnum)
DidAnimateAttr(this);
}
void
nsSVGFE::DidAnimateBoolean(PRUint8 aAttrEnum)
{
DidAnimateAttr(this);
}
//---------------------Gaussian Blur------------------------
typedef nsSVGFE nsSVGFEGaussianBlurElementBase;
@ -3826,7 +3832,7 @@ public:
protected:
virtual PRBool OperatesOnPremultipledAlpha() {
return !mBooleanAttributes[PRESERVEALPHA].GetAnimValue();
return !mBooleanAttributes[PRESERVEALPHA].GetAnimValue(this);
}
virtual NumberAttributesInfo GetNumberInfo();
@ -4190,7 +4196,7 @@ nsSVGFEConvolveMatrixElement::Filter(nsSVGFilterInstance *instance,
return NS_ERROR_FAILURE;
PRUint16 edgeMode = mEnumAttributes[EDGEMODE].GetAnimValue(this);
PRBool preserveAlpha = mBooleanAttributes[PRESERVEALPHA].GetAnimValue();
PRBool preserveAlpha = mBooleanAttributes[PRESERVEALPHA].GetAnimValue(this);
float bias = 0;
if (HasAttr(kNameSpaceID_None, nsGkAtoms::bias)) {

Просмотреть файл

@ -220,6 +220,7 @@ protected:
virtual void DidAnimateLength(PRUint8 aAttrEnum);
virtual void DidAnimateNumber(PRUint8 aAttrEnum);
virtual void DidAnimateEnum(PRUint8 aAttrEnum);
virtual void DidAnimateBoolean(PRUint8 aAttrEnum);
// nsIDOMSVGFitlerPrimitiveStandardAttributes values
enum { X, Y, WIDTH, HEIGHT };

Просмотреть файл

@ -0,0 +1,41 @@
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class="reftest-wait"
onload="setTimeAndSnapshot(1, true)">
<title>Test animation of the "preserveAlpha" &lt;boolean&gt; attribute on the "feConvolveMatrix" element</title>
<script xlink:href="smil-util.js" type="text/javascript"/>
<filter id="convolve_1">
<feConvolveMatrix order="2 2" kernelMatrix="0 0 0 0" preserveAlpha="true">
<!-- turn the referencing element from transparent to red at 1.25s -->
<animate attributeName="preserveAlpha"
calcMode="discrete"
begin="0s" dur="2.5s"
from="false" to="true"
fill="freeze"/>
</feConvolveMatrix>
<feColorMatrix type="matrix"
values="0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0"/>
</filter>
<filter id="convolve_2">
<feConvolveMatrix order="2 2" kernelMatrix="0 0 0 0" preserveAlpha="true">
<!-- turn the referencing element from red to transparent at 1s -->
<animate attributeName="preserveAlpha"
calcMode="discrete"
begin="0s" dur="2s"
from="true" to="false"
fill="freeze"/>
</feConvolveMatrix>
<feColorMatrix type="matrix"
values="0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0"/>
</filter>
<rect width="100%" height="100%" fill="lime"/>
<!-- 40% through discrete animation simple duration -
tests that the animation doesn't affect the element too early -->
<rect width="100" height="50" fill="red" filter="url(#convolve_1)"/>
<!-- 50% through discrete animation simple duration -
tests that the animation affects the element now -->
<rect y="50" width="100" height="50" fill="red" filter="url(#convolve_2)"/>
</svg>

После

Ширина:  |  Высота:  |  Размер: 1.8 KiB

Просмотреть файл

@ -85,6 +85,9 @@ fails == anim-fillopacity-1xml.svg anim-standard-ref.svg # bug 534028
== anim-feComposite-operator-01.svg lime.svg
== anim-filter-filterUnits-01.svg lime.svg
# animate some boolean attributes:
== anim-feConvolveMatrix-preserveAlpha-01.svg lime.svg
== anim-remove-1.svg anim-standard-ref.svg
== anim-remove-2.svg anim-standard-ref.svg
== anim-remove-3.svg anim-standard-ref.svg