Bug 540478, part 2 of 2. Add support for SMIL animation of enumeration attributes in SVG. r=dholbert

This commit is contained in:
Jonathan Watt 2010-01-23 18:59:03 +00:00
Родитель 1933c6cb14
Коммит fd937563cb
15 изменённых файлов: 454 добавлений и 26 удалений

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

@ -70,6 +70,7 @@ CPPSRCS += \
nsSMILTimeValue.cpp \
nsSMILTimeValueSpec.cpp \
nsSMILValue.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 "SMILEnumType.h"
#include "nsSMILValue.h"
#include "nsDebug.h"
#include <math.h>
namespace mozilla {
/*static*/ SMILEnumType SMILEnumType::sSingleton;
nsresult
SMILEnumType::Init(nsSMILValue& aValue) const
{
NS_PRECONDITION(aValue.mType == this || aValue.IsNull(),
"Unexpected value type");
aValue.mU.mUint = 0;
aValue.mType = this;
return NS_OK;
}
void
SMILEnumType::Destroy(nsSMILValue& aValue) const
{
NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value.");
aValue.mU.mUint = 0;
aValue.mType = &nsSMILNullType::sSingleton;
}
nsresult
SMILEnumType::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.mUint = aSrc.mU.mUint;
return NS_OK;
}
nsresult
SMILEnumType::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; // enum values can't be added to each other
}
nsresult
SMILEnumType::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 enum values
}
nsresult
SMILEnumType::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; // enum 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_SMILENUMTYPE_H_
#define MOZILLA_SMILENUMTYPE_H_
#include "nsISMILType.h"
namespace mozilla {
class SMILEnumType : 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 SMILEnumType sSingleton;
private:
SMILEnumType() {}
};
} // namespace mozilla
#endif // MOZILLA_SMILENUMTYPE_H_

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

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

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

@ -1454,6 +1454,19 @@ nsSVGElement::DidChangeEnum(PRUint8 aAttrEnum, PRBool aDoSetAttr)
newStr, PR_TRUE);
}
void
nsSVGElement::DidAnimateEnum(PRUint8 aAttrEnum)
{
nsIFrame* frame = GetPrimaryFrame();
if (frame) {
EnumAttributesInfo info = GetEnumInfo();
frame->AttributeChanged(kNameSpaceID_None,
*info.mEnumInfo[aAttrEnum].mName,
nsIDOMMutationEvent::MODIFICATION);
}
}
nsSVGViewBox *
nsSVGElement::GetViewBox()
{
@ -1703,6 +1716,16 @@ nsSVGElement::GetAnimatedAttr(const nsIAtom* aName)
}
}
// Enumerations:
{
EnumAttributesInfo info = GetEnumInfo();
for (PRUint32 i = 0; i < info.mEnumCount; i++) {
if (aName == *info.mEnumInfo[i].mName) {
return info.mEnums[i].ToSMILAttr(this);
}
}
}
return nsnull;
}

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

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

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

@ -37,6 +37,12 @@
#include "nsSVGEnum.h"
#include "nsIAtom.h"
#include "nsSVGElement.h"
#ifdef MOZ_SMIL
#include "nsSMILValue.h"
#include "SMILEnumType.h"
#endif // MOZ_SMIL
using namespace mozilla;
NS_SVG_VAL_IMPL_CYCLE_COLLECTION(nsSVGEnum::DOMAnimatedEnum, mSVGElement)
@ -67,14 +73,21 @@ nsSVGEnum::SetBaseValueString(const nsAString& aValue,
{
nsCOMPtr<nsIAtom> valAtom = do_GetAtom(aValue);
nsSVGEnumMapping *tmp = GetMapping(aSVGElement);
nsSVGEnumMapping *mapping = GetMapping(aSVGElement);
while (tmp && tmp->mKey) {
if (valAtom == *(tmp->mKey)) {
mBaseVal = mAnimVal = tmp->mVal;
while (mapping && mapping->mKey) {
if (valAtom == *(mapping->mKey)) {
if (mBaseVal != mapping->mVal) {
mBaseVal = mAnimVal = mapping->mVal;
#ifdef MOZ_SMIL
if (mIsAnimated) {
aSVGElement->AnimationNeedsResample();
}
#endif
}
return NS_OK;
}
tmp++;
mapping++;
}
// only a warning since authors may mistype attribute values
@ -85,14 +98,14 @@ nsSVGEnum::SetBaseValueString(const nsAString& aValue,
void
nsSVGEnum::GetBaseValueString(nsAString& aValue, nsSVGElement *aSVGElement)
{
nsSVGEnumMapping *tmp = GetMapping(aSVGElement);
nsSVGEnumMapping *mapping = GetMapping(aSVGElement);
while (tmp && tmp->mKey) {
if (mBaseVal == tmp->mVal) {
(*tmp->mKey)->ToString(aValue);
while (mapping && mapping->mKey) {
if (mBaseVal == mapping->mVal) {
(*mapping->mKey)->ToString(aValue);
return;
}
tmp++;
mapping++;
}
NS_ERROR("unknown enumeration value");
}
@ -102,19 +115,34 @@ nsSVGEnum::SetBaseValue(PRUint16 aValue,
nsSVGElement *aSVGElement,
PRBool aDoSetAttr)
{
nsSVGEnumMapping *tmp = GetMapping(aSVGElement);
nsSVGEnumMapping *mapping = GetMapping(aSVGElement);
while (tmp && tmp->mKey) {
if (tmp->mVal == aValue) {
mAnimVal = mBaseVal = PRUint8(aValue);
aSVGElement->DidChangeEnum(mAttrEnum, aDoSetAttr);
while (mapping && mapping->mKey) {
if (mapping->mVal == aValue) {
if (mBaseVal != PRUint8(aValue)) {
mBaseVal = mAnimVal = PRUint8(aValue);
aSVGElement->DidChangeEnum(mAttrEnum, aDoSetAttr);
#ifdef MOZ_SMIL
if (mIsAnimated) {
aSVGElement->AnimationNeedsResample();
}
#endif
}
return NS_OK;
}
tmp++;
mapping++;
}
return NS_ERROR_DOM_SYNTAX_ERR;
}
void
nsSVGEnum::SetAnimValue(PRUint16 aValue, nsSVGElement *aSVGElement)
{
mAnimVal = aValue;
mIsAnimated = PR_TRUE;
aSVGElement->DidAnimateEnum(mAttrEnum);
}
nsresult
nsSVGEnum::ToDOMAnimatedEnum(nsIDOMSVGAnimatedEnumeration **aResult,
nsSVGElement *aSVGElement)
@ -126,3 +154,64 @@ nsSVGEnum::ToDOMAnimatedEnum(nsIDOMSVGAnimatedEnumeration **aResult,
NS_ADDREF(*aResult);
return NS_OK;
}
#ifdef MOZ_SMIL
nsISMILAttr*
nsSVGEnum::ToSMILAttr(nsSVGElement *aSVGElement)
{
return new SMILEnum(this, aSVGElement);
}
nsresult
nsSVGEnum::SMILEnum::ValueFromString(const nsAString& aStr,
const nsISMILAnimationElement* /*aSrcElement*/,
nsSMILValue& aValue) const
{
nsCOMPtr<nsIAtom> valAtom = do_GetAtom(aStr);
nsSVGEnumMapping *mapping = mVal->GetMapping(mSVGElement);
while (mapping && mapping->mKey) {
if (valAtom == *(mapping->mKey)) {
nsSMILValue val(&SMILEnumType::sSingleton);
val.mU.mUint = mapping->mVal;
aValue = val;
return NS_OK;
}
mapping++;
}
// only a warning since authors may mistype attribute values
NS_WARNING("unknown enumeration key");
return NS_ERROR_FAILURE;
}
nsSMILValue
nsSVGEnum::SMILEnum::GetBaseValue() const
{
nsSMILValue val(&SMILEnumType::sSingleton);
val.mU.mUint = mVal->mBaseVal;
return val;
}
void
nsSVGEnum::SMILEnum::ClearAnimValue()
{
if (mVal->mIsAnimated) {
mVal->SetAnimValue(mVal->mBaseVal, mSVGElement);
mVal->mIsAnimated = PR_FALSE;
}
}
nsresult
nsSVGEnum::SMILEnum::SetAnimValue(const nsSMILValue& aValue)
{
NS_ASSERTION(aValue.mType == &SMILEnumType::sSingleton,
"Unexpected type to assign animated value");
if (aValue.mType == &SMILEnumType::sSingleton) {
NS_ABORT_IF_FALSE(aValue.mU.mUint <= USHRT_MAX,
"Very large enumerated value - too big for PRUint16");
mVal->SetAnimValue(PRUint16(aValue.mU.mUint), mSVGElement);
}
return NS_OK;
}
#endif // MOZ_SMIL

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

@ -54,6 +54,7 @@ public:
void Init(PRUint8 aAttrEnum, PRUint16 aValue) {
mAnimVal = mBaseVal = PRUint8(aValue);
mAttrEnum = aAttrEnum;
mIsAnimated = PR_FALSE;
}
nsresult SetBaseValueString(const nsAString& aValue,
@ -65,19 +66,30 @@ public:
nsresult SetBaseValue(PRUint16 aValue,
nsSVGElement *aSVGElement,
PRBool aDoSetAttr);
PRUint16 GetBaseValue() const
{ return mBaseVal; }
void SetAnimValue(PRUint16 aValue, nsSVGElement *aSVGElement);
PRUint16 GetAnimValue(nsSVGElement *aSVGElement) const
{ return mAnimVal; }
{
#ifdef MOZ_SMIL
aSVGElement->FlushAnimations();
#endif
return mAnimVal;
}
nsresult ToDOMAnimatedEnum(nsIDOMSVGAnimatedEnumeration **aResult,
nsSVGElement* aSVGElement);
#ifdef MOZ_SMIL
// Returns a new nsISMILAttr object that the caller must delete
nsISMILAttr* ToSMILAttr(nsSVGElement* aSVGElement);
#endif // MOZ_SMIL
private:
nsSVGEnumValue mAnimVal;
nsSVGEnumValue mBaseVal;
PRUint8 mAttrEnum; // element specified tracking for attribute
PRPackedBool mIsAnimated;
nsSVGEnumMapping *GetMapping(nsSVGElement *aSVGElement);
@ -99,6 +111,29 @@ private:
NS_IMETHOD GetAnimVal(PRUint16* aResult)
{ *aResult = mVal->GetAnimValue(mSVGElement); return NS_OK; }
};
#ifdef MOZ_SMIL
struct SMILEnum : public nsISMILAttr
{
public:
SMILEnum(nsSVGEnum* 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.
nsSVGEnum* 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_SVGENUM_H__

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

@ -247,3 +247,13 @@ nsSVGFilterElement::DidAnimateLength(PRUint8 aAttrEnum)
nsSVGEffects::InvalidateRenderingObservers(frame);
}
}
void
nsSVGFilterElement::DidAnimateEnum(PRUint8 aAttrEnum)
{
// nsSVGFilterFrame does not implement a useful AttributeChanged
nsIFrame* frame = GetPrimaryFrame();
if (frame) {
nsSVGEffects::InvalidateRenderingObservers(frame);
}
}

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

@ -88,6 +88,7 @@ protected:
virtual StringAttributesInfo GetStringInfo();
virtual void DidAnimateLength(PRUint8 aAttrEnum);
virtual void DidAnimateEnum(PRUint8 aAttrEnum);
enum { X, Y, WIDTH, HEIGHT };
nsSVGLength2 mLengthAttributes[4];

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

@ -302,24 +302,31 @@ nsSVGFE::GetLengthInfo()
NS_ARRAY_LENGTH(sLengthInfo));
}
void
nsSVGFE::DidAnimateLength(PRUint8 aAttrEnum)
inline static void DidAnimateAttr(nsSVGFE *aFilterPrimitive)
{
// nsSVGLeafFrame doesn't implement AttributeChanged.
nsIFrame* frame = GetPrimaryFrame();
nsIFrame* frame = aFilterPrimitive->GetPrimaryFrame();
if (frame) {
nsSVGEffects::InvalidateRenderingObservers(frame);
}
}
void
nsSVGFE::DidAnimateLength(PRUint8 aAttrEnum)
{
DidAnimateAttr(this);
}
void
nsSVGFE::DidAnimateNumber(PRUint8 aAttrEnum)
{
// nsSVGLeafFrame doesn't implement AttributeChanged.
nsIFrame* frame = GetPrimaryFrame();
if (frame) {
nsSVGEffects::InvalidateRenderingObservers(frame);
}
DidAnimateAttr(this);
}
void
nsSVGFE::DidAnimateEnum(PRUint8 aAttrEnum)
{
DidAnimateAttr(this);
}
//---------------------Gaussian Blur------------------------

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

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

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

@ -0,0 +1,38 @@
<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 "operator" enum attribute on the "feComposite" element</title>
<script xlink:href="smil-util.js" type="text/javascript"/>
<filter id="composite_filter_1" x="-100%" y="0%" width="200%" height="100%">
<feFlood flood-color="lime" result="lime"/>
<feComposite in="lime" in2="SourceGraphic" operator="out">
<!-- this should turn the referencing element red at 1.25s -->
<animate attributeName="operator"
calcMode="discrete"
begin="0s" dur="2.5s"
from="out" to="in"
fill="freeze"/>
</feComposite>
</filter>
<filter id="composite_filter_2" x="0%" y="0%" width="200%" height="100%">
<feFlood flood-color="lime" result="lime"/>
<feComposite in="lime" in2="SourceGraphic" operator="out">
<!-- this should turn the referencing element lime at 1s -->
<animate attributeName="operator"
calcMode="discrete"
begin="0s" dur="2s"
from="out" to="in"
fill="freeze"/>
</feComposite>
</filter>
<rect width="100%" height="100%" fill="lime"/>
<!-- 40% through discrete animation simple duration - test animation doesn't affect the element too early -->
<rect width="100" height="100" fill="red"/>
<rect x="100" width="100" height="100" fill="red" filter="url(#composite_filter_1)"/>
<!-- 50% through discrete animation simple duration - test animation affects the element now -->
<rect y="100" width="100" height="100" fill="red"/>
<rect y="100" width="100" height="100" fill="red" filter="url(#composite_filter_2)"/>
</svg>

После

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

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

@ -0,0 +1,42 @@
<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 "filterUnits" enum attributes of the "filter" element</title>
<script xlink:href="smil-util.js" type="text/javascript"/>
<filter id="flood_filter_1" filterUnits="userSpaceOnUse"
x="0%" y="0%" width="100%" height="100%">
<!-- this should reduce the referencing element to 50% of the
viewport width at 1.25s -->
<animate attributeName="filterUnits"
calcMode="discrete"
begin="0s" dur="2.5s"
from="userSpaceOnUse" to="objectBoundingBox"
fill="freeze"/>
<feFlood width="100%" height="100%" flood-color="lime"/>
</filter>
<filter id="flood_filter_2" x="0%" y="0%" width="100%" height="100%">
<!-- this should expand the referencing element to 100% of the
viewport width at 1s -->
<animate attributeName="filterUnits"
calcMode="discrete"
begin="0s" dur="2s"
from="objectBoundingBox" to="userSpaceOnUse"
fill="freeze"/>
<feFlood width="100%" height="100%" flood-color="lime"/>
</filter>
<rect width="100%" height="100%" fill="lime"/>
<rect width="100%" height="100" fill="red"/>
<!-- 40% through discrete animation simple duration -
tests animation doesn't affect the element too early -->
<svg height="50">
<rect width="50%" height="100%" fill="red" filter="url(#flood_filter_1)"/>
</svg>
<!-- 50% through discrete animation simple duration -
tests animation affects the element now -->
<svg y="50" height="50">
<rect width="50%" height="100%" fill="red" filter="url(#flood_filter_2)"/>
</svg>
</svg>

После

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

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

@ -81,6 +81,10 @@ 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 enumeration attributes:
== anim-feComposite-operator-01.svg lime.svg
== anim-filter-filterUnits-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