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

This commit is contained in:
Jonathan Watt 2010-02-18 21:50:59 +00:00
Родитель 5291f401f2
Коммит ecd0d20033
14 изменённых файлов: 552 добавлений и 37 удалений

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

@ -73,6 +73,11 @@ public:
PRUint64 mUint;
PRInt64 mInt;
double mDouble;
struct {
float mAngle;
PRUint16 mUnit;
PRUint16 mOrientType;
} mOrient;
void* mPtr;
} mU;
const nsISMILType* mType;

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

@ -129,6 +129,7 @@ CPPSRCS += nsSVGAnimateElement.cpp \
nsSVGSetElement.cpp \
nsSVGTransformSMILType.cpp \
nsSVGTransformSMILAttr.cpp \
SVGOrientSMILType.cpp \
$(NULL)
endif

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

@ -0,0 +1,169 @@
/* -*- 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 "SVGOrientSMILType.h"
#include "nsSMILValue.h"
#include "nsSVGViewBox.h"
#include "nsSVGAngle.h"
#include "nsIDOMSVGMarkerElement.h"
#include "nsDebug.h"
#include <math.h>
namespace mozilla {
/*static*/ SVGOrientSMILType SVGOrientSMILType::sSingleton;
nsresult
SVGOrientSMILType::Init(nsSMILValue& aValue) const
{
NS_ABORT_IF_FALSE(aValue.IsNull(), "Unexpected value type");
aValue.mU.mOrient.mAngle = 0.0f;
aValue.mU.mOrient.mUnit = nsIDOMSVGAngle::SVG_ANGLETYPE_UNSPECIFIED;
aValue.mU.mOrient.mOrientType = nsIDOMSVGMarkerElement::SVG_MARKER_ORIENT_ANGLE;
aValue.mType = this;
return NS_OK;
}
void
SVGOrientSMILType::Destroy(nsSMILValue& aValue) const
{
NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value.");
aValue.mU.mPtr = nsnull;
aValue.mType = &nsSMILNullType::sSingleton;
}
nsresult
SVGOrientSMILType::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.mOrient.mAngle = aSrc.mU.mOrient.mAngle;
aDest.mU.mOrient.mUnit = aSrc.mU.mOrient.mUnit;
aDest.mU.mOrient.mOrientType = aSrc.mU.mOrient.mOrientType;
return NS_OK;
}
nsresult
SVGOrientSMILType::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");
if (aDest.mU.mOrient.mOrientType != nsIDOMSVGMarkerElement::SVG_MARKER_ORIENT_ANGLE ||
aValueToAdd.mU.mOrient.mOrientType != nsIDOMSVGMarkerElement::SVG_MARKER_ORIENT_ANGLE) {
// TODO: it would be nice to be able to add to auto angles
return NS_ERROR_FAILURE;
}
// We may be dealing with two different angle units, so we normalize to
// degrees for the add:
float currentAngle = aDest.mU.mOrient.mAngle *
nsSVGAngle::GetDegreesPerUnit(aDest.mU.mOrient.mUnit);
float angleToAdd = aValueToAdd.mU.mOrient.mAngle *
nsSVGAngle::GetDegreesPerUnit(aValueToAdd.mU.mOrient.mUnit) *
aCount;
// And then we give the resulting animated value the same units as the value
// that we're animating to/by (i.e. the same as aValueToAdd):
aDest.mU.mOrient.mAngle = (currentAngle + angleToAdd) /
nsSVGAngle::GetDegreesPerUnit(aValueToAdd.mU.mOrient.mUnit);
aDest.mU.mOrient.mUnit = aValueToAdd.mU.mOrient.mUnit;
return NS_OK;
}
nsresult
SVGOrientSMILType::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");
if (aFrom.mU.mOrient.mOrientType != nsIDOMSVGMarkerElement::SVG_MARKER_ORIENT_ANGLE ||
aTo.mU.mOrient.mOrientType != nsIDOMSVGMarkerElement::SVG_MARKER_ORIENT_ANGLE) {
// TODO: it would be nice to be able to compute distance with auto angles
return NS_ERROR_FAILURE;
}
// Normalize both to degrees in case they're different angle units:
double from = aFrom.mU.mOrient.mAngle *
nsSVGAngle::GetDegreesPerUnit(aFrom.mU.mOrient.mUnit);
double to = aTo.mU.mOrient.mAngle *
nsSVGAngle::GetDegreesPerUnit(aTo.mU.mOrient.mUnit);
aDistance = fabs(to - from);
return NS_OK;
}
nsresult
SVGOrientSMILType::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.");
if (aStartVal.mU.mOrient.mOrientType != nsIDOMSVGMarkerElement::SVG_MARKER_ORIENT_ANGLE ||
aStartVal.mU.mOrient.mOrientType != nsIDOMSVGMarkerElement::SVG_MARKER_ORIENT_ANGLE) {
// TODO: it would be nice to be able to handle auto angles too.
return NS_ERROR_FAILURE;
}
float start = aStartVal.mU.mOrient.mAngle *
nsSVGAngle::GetDegreesPerUnit(aStartVal.mU.mOrient.mUnit);
float end = aEndVal.mU.mOrient.mAngle *
nsSVGAngle::GetDegreesPerUnit(aEndVal.mU.mOrient.mUnit);
float result = (start + (end - start) * aUnitDistance);
// Again, we use the unit of the to/by value for the result:
aResult.mU.mOrient.mAngle = result /
nsSVGAngle::GetDegreesPerUnit(aEndVal.mU.mOrient.mUnit);
aResult.mU.mOrient.mUnit = aEndVal.mU.mOrient.mUnit;
return NS_OK;
}
} // namespace mozilla

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

@ -0,0 +1,89 @@
/* -*- 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_SVGORIENTSMILTYPE_H_
#define MOZILLA_SVGORIENTSMILTYPE_H_
#include "nsISMILType.h"
/**
* This nsISMILType class is a special case for the 'orient' attribute on SVG's
* 'marker' element.
*
* orient = "auto | <angle>"
*
* Unusually, this attribute doesn't have just a single corresponding DOM
* property, but rather is split into two properties: 'orientType' (of type
* SVGAnimatedEnumeration) and 'orientAngle' (of type SVGAnimatedAngle). If
* 'orientType.animVal' is not SVG_MARKER_ORIENT_AUTO, then
* 'orientAngle.animVal' contains the angle that is being used. The lacuna
* value is 0.
*/
namespace mozilla {
class SVGOrientSMILType : public nsISMILType
{
public:
// Singleton for nsSMILValue objects to hold onto.
static SVGOrientSMILType sSingleton;
protected:
// nsISMILType Methods
// -------------------
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;
private:
// Private constructor & destructor: prevent instances beyond my singleton,
// and prevent others from deleting my singleton.
SVGOrientSMILType() {}
~SVGOrientSMILType() {}
};
} // namespace mozilla
#endif // MOZILLA_SVGORIENTSMILTYPE_H_

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

@ -38,7 +38,22 @@
#include "prdtoa.h"
#include "nsTextFormatter.h"
#include "nsSVGUtils.h"
#include "nsSVGMarkerElement.h"
#ifdef MOZ_SMIL
#include "nsSMILValue.h"
#include "SVGOrientSMILType.h"
#endif // MOZ_SMIL
using namespace mozilla;
/**
* Mutable SVGAngle class for SVGSVGElement.createSVGAngle().
*
* Note that this class holds its own nsSVGAngle, which therefore can't be
* animated. This means SVGMarkerElement::setOrientToAngle(angle) must copy
* any DOMSVGAngle passed in. Perhaps this is wrong and inconsistent with
* other parts of SVG, but it's how the code works for now.
*/
class DOMSVGAngle : public nsIDOMSVGAngle
{
public:
@ -48,7 +63,7 @@ public:
{ mVal.Init(); }
NS_IMETHOD GetUnitType(PRUint16* aResult)
{ *aResult = mVal.mSpecifiedUnitType; return NS_OK; }
{ *aResult = mVal.mBaseValUnit; return NS_OK; }
NS_IMETHOD GetValue(float* aResult)
{ *aResult = mVal.GetBaseValue(); return NS_OK; }
@ -217,17 +232,17 @@ GetValueFromString(const nsAString &aValueAsString,
return NS_ERROR_DOM_SYNTAX_ERR;
}
float
nsSVGAngle::GetUnitScaleFactor() const
/* static */ float
nsSVGAngle::GetDegreesPerUnit(PRUint8 aUnit)
{
switch (mSpecifiedUnitType) {
switch (aUnit) {
case nsIDOMSVGAngle::SVG_ANGLETYPE_UNSPECIFIED:
case nsIDOMSVGAngle::SVG_ANGLETYPE_DEG:
return 1;
case nsIDOMSVGAngle::SVG_ANGLETYPE_RAD:
return static_cast<float>(M_PI / 180.0);
return static_cast<float>(180.0 / M_PI);
case nsIDOMSVGAngle::SVG_ANGLETYPE_GRAD:
return 100.0f / 180.0f;
return 180.0f / 100.0f;
default:
NS_NOTREACHED("Unknown unit type");
return 0;
@ -239,6 +254,14 @@ nsSVGAngle::SetBaseValueInSpecifiedUnits(float aValue,
nsSVGElement *aSVGElement)
{
mBaseVal = aValue;
if (!mIsAnimated) {
mAnimVal = mBaseVal;
}
#ifdef MOZ_SMIL
else {
aSVGElement->AnimationNeedsResample();
}
#endif
aSVGElement->DidChangeAngle(mAttrEnum, PR_TRUE);
}
@ -249,8 +272,8 @@ nsSVGAngle::ConvertToSpecifiedUnits(PRUint16 unitType,
if (!IsValidUnitType(unitType))
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
float valueInUserUnits = mBaseVal / GetUnitScaleFactor();
mSpecifiedUnitType = PRUint8(unitType);
float valueInUserUnits = mBaseVal * GetDegreesPerUnit(mBaseValUnit);
mBaseValUnit = PRUint8(unitType);
SetBaseValue(valueInUserUnits, aSVGElement);
return NS_OK;
}
@ -265,11 +288,18 @@ nsSVGAngle::NewValueSpecifiedUnits(PRUint16 unitType,
if (!IsValidUnitType(unitType))
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
mBaseVal = mAnimVal = valueInSpecifiedUnits;
mSpecifiedUnitType = PRUint8(unitType);
if (aSVGElement) {
aSVGElement->DidChangeAngle(mAttrEnum, PR_TRUE);
mBaseVal = valueInSpecifiedUnits;
mBaseValUnit = PRUint8(unitType);
if (!mIsAnimated) {
mAnimVal = mBaseVal;
mAnimValUnit = mBaseValUnit;
}
#ifdef MOZ_SMIL
else {
aSVGElement->AnimationNeedsResample();
}
#endif
aSVGElement->DidChangeAngle(mAttrEnum, PR_TRUE);
return NS_OK;
}
@ -310,8 +340,17 @@ nsSVGAngle::SetBaseValueString(const nsAString &aValueAsString,
return rv;
}
mBaseVal = mAnimVal = value;
mSpecifiedUnitType = PRUint8(unitType);
mBaseVal = value;
mBaseValUnit = PRUint8(unitType);
if (!mIsAnimated) {
mAnimVal = mBaseVal;
mAnimValUnit = mBaseValUnit;
}
#ifdef MOZ_SMIL
else {
aSVGElement->AnimationNeedsResample();
}
#endif
// We don't need to call DidChange* here - we're only called by
// nsSVGElement::ParseAttribute under nsGenericElement::SetAttr,
@ -322,24 +361,41 @@ nsSVGAngle::SetBaseValueString(const nsAString &aValueAsString,
void
nsSVGAngle::GetBaseValueString(nsAString & aValueAsString)
{
GetValueString(aValueAsString, mBaseVal, mSpecifiedUnitType);
GetValueString(aValueAsString, mBaseVal, mBaseValUnit);
}
void
nsSVGAngle::GetAnimValueString(nsAString & aValueAsString)
{
GetValueString(aValueAsString, mAnimVal, mSpecifiedUnitType);
GetValueString(aValueAsString, mAnimVal, mAnimValUnit);
}
void
nsSVGAngle::SetBaseValue(float aValue, nsSVGElement *aSVGElement)
{
mAnimVal = mBaseVal = aValue * GetUnitScaleFactor();
mBaseVal = aValue / GetDegreesPerUnit(mBaseValUnit);
if (!mIsAnimated) {
mAnimVal = mBaseVal;
}
#ifdef MOZ_SMIL
else if (aSVGElement) {
aSVGElement->AnimationNeedsResample();
}
#endif
if (aSVGElement) {
aSVGElement->DidChangeAngle(mAttrEnum, PR_TRUE);
}
}
void
nsSVGAngle::SetAnimValue(float aValue, PRUint8 aUnit, nsSVGElement *aSVGElement)
{
mAnimVal = aValue;
mAnimValUnit = aUnit;
mIsAnimated = PR_TRUE;
aSVGElement->DidAnimateAngle(mAttrEnum);
}
nsresult
nsSVGAngle::ToDOMAnimatedAngle(nsIDOMSVGAnimatedAngle **aResult,
nsSVGElement *aSVGElement)
@ -362,3 +418,79 @@ NS_NewDOMSVGAngle(nsIDOMSVGAngle** aResult)
NS_ADDREF(*aResult);
return NS_OK;
}
#ifdef MOZ_SMIL
nsISMILAttr*
nsSVGAngle::ToSMILAttr(nsSVGElement *aSVGElement)
{
if (aSVGElement->NodeInfo()->Equals(nsGkAtoms::marker, kNameSpaceID_SVG)) {
nsSVGMarkerElement *marker = static_cast<nsSVGMarkerElement*>(aSVGElement);
return new SMILOrient(marker->GetOrientType(), this, aSVGElement);
}
// SMILOrient would not be useful for general angle attributes (also,
// "orient" is the only animatable <angle>-valued attribute in SVG 1.1).
NS_NOTREACHED("Trying to animate unknown angle attribute.");
return nsnull;
}
nsresult
nsSVGAngle::SMILOrient::ValueFromString(const nsAString& aStr,
const nsISMILAnimationElement* /*aSrcElement*/,
nsSMILValue& aValue) const
{
nsSMILValue val(&SVGOrientSMILType::sSingleton);
if (aStr.EqualsLiteral("auto")) {
val.mU.mOrient.mOrientType = nsIDOMSVGMarkerElement::SVG_MARKER_ORIENT_AUTO;
} else {
float value;
PRUint16 unitType;
nsresult rv = GetValueFromString(aStr, &value, &unitType);
if (NS_FAILED(rv)) {
return rv;
}
val.mU.mOrient.mAngle = value;
val.mU.mOrient.mUnit = unitType;
val.mU.mOrient.mOrientType = nsIDOMSVGMarkerElement::SVG_MARKER_ORIENT_ANGLE;
}
aValue = val;
return NS_OK;
}
nsSMILValue
nsSVGAngle::SMILOrient::GetBaseValue() const
{
nsSMILValue val(&SVGOrientSMILType::sSingleton);
val.mU.mOrient.mAngle = mAngle->GetBaseValInSpecifiedUnits();
val.mU.mOrient.mUnit = mAngle->GetBaseValueUnit();
val.mU.mOrient.mOrientType = mOrientType->GetBaseValue();
return val;
}
void
nsSVGAngle::SMILOrient::ClearAnimValue()
{
if (mAngle->mIsAnimated) {
mOrientType->SetAnimValue(mOrientType->GetBaseValue());
mAngle->SetAnimValue(mAngle->mBaseVal, mAngle->mBaseValUnit, mSVGElement);
mAngle->mIsAnimated = PR_FALSE;
}
}
nsresult
nsSVGAngle::SMILOrient::SetAnimValue(const nsSMILValue& aValue)
{
NS_ASSERTION(aValue.mType == &SVGOrientSMILType::sSingleton,
"Unexpected type to assign animated value");
if (aValue.mType == &SVGOrientSMILType::sSingleton) {
mOrientType->SetAnimValue(aValue.mU.mOrient.mOrientType);
if (aValue.mU.mOrient.mOrientType == nsIDOMSVGMarkerElement::SVG_MARKER_ORIENT_AUTO) {
mAngle->SetAnimValue(0.0f, nsIDOMSVGAngle::SVG_ANGLETYPE_UNSPECIFIED, mSVGElement);
} else {
mAngle->SetAnimValue(aValue.mU.mOrient.mAngle, aValue.mU.mOrient.mUnit, mSVGElement);
}
}
return NS_OK;
}
#endif // MOZ_SMIL

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

@ -42,6 +42,8 @@
#include "nsSVGElement.h"
#include "nsDOMError.h"
class nsSVGOrientType;
class nsSVGAngle
{
friend class DOMSVGAngle;
@ -51,8 +53,9 @@ public:
float aValue = 0,
PRUint8 aUnitType = nsIDOMSVGAngle::SVG_ANGLETYPE_UNSPECIFIED) {
mAnimVal = mBaseVal = aValue;
mSpecifiedUnitType = aUnitType;
mAnimValUnit = mBaseValUnit = aUnitType;
mAttrEnum = aAttrEnum;
mIsAnimated = PR_FALSE;
}
nsresult SetBaseValueString(const nsAString& aValue,
@ -62,28 +65,37 @@ public:
void GetAnimValueString(nsAString& aValue);
float GetBaseValue() const
{ return mBaseVal / GetUnitScaleFactor(); }
{ return mBaseVal * GetDegreesPerUnit(mBaseValUnit); }
float GetAnimValue() const
{ return mAnimVal / GetUnitScaleFactor(); }
{ return mAnimVal * GetDegreesPerUnit(mAnimValUnit); }
void SetBaseValue(float aValue, nsSVGElement *aSVGElement);
void SetAnimValue(float aValue, PRUint8 aUnit, nsSVGElement *aSVGElement);
PRUint8 GetSpecifiedUnitType() const { return mSpecifiedUnitType; }
float GetAnimValInSpecifiedUnits() const { return mAnimVal; }
PRUint8 GetBaseValueUnit() const { return mBaseValUnit; }
PRUint8 GetAnimValueUnit() const { return mAnimValUnit; }
float GetBaseValInSpecifiedUnits() const { return mBaseVal; }
float GetAnimValInSpecifiedUnits() const { return mAnimVal; }
static nsresult ToDOMSVGAngle(nsIDOMSVGAngle **aResult);
nsresult ToDOMAnimatedAngle(nsIDOMSVGAnimatedAngle **aResult,
nsSVGElement* aSVGElement);
#ifdef MOZ_SMIL
// Returns a new nsISMILAttr object that the caller must delete
nsISMILAttr* ToSMILAttr(nsSVGElement* aSVGElement);
#endif // MOZ_SMIL
static float GetDegreesPerUnit(PRUint8 aUnit);
private:
float mAnimVal;
float mBaseVal;
PRUint8 mSpecifiedUnitType;
PRUint8 mAnimValUnit;
PRUint8 mBaseValUnit;
PRUint8 mAttrEnum; // element specified tracking for attribute
PRPackedBool mIsAnimated;
float GetUnitScaleFactor() const;
void SetBaseValueInSpecifiedUnits(float aValue, nsSVGElement *aSVGElement);
nsresult NewValueSpecifiedUnits(PRUint16 aUnitType, float aValue,
nsSVGElement *aSVGElement);
@ -103,7 +115,7 @@ private:
nsRefPtr<nsSVGElement> mSVGElement;
NS_IMETHOD GetUnitType(PRUint16* aResult)
{ *aResult = mVal->mSpecifiedUnitType; return NS_OK; }
{ *aResult = mVal->mBaseValUnit; return NS_OK; }
NS_IMETHOD GetValue(float* aResult)
{ *aResult = mVal->GetBaseValue(); return NS_OK; }
@ -142,7 +154,7 @@ private:
nsRefPtr<nsSVGElement> mSVGElement;
NS_IMETHOD GetUnitType(PRUint16* aResult)
{ *aResult = mVal->mSpecifiedUnitType; return NS_OK; }
{ *aResult = mVal->mAnimValUnit; return NS_OK; }
NS_IMETHOD GetValue(float* aResult)
{ *aResult = mVal->GetAnimValue(); return NS_OK; }
@ -184,6 +196,40 @@ private:
NS_IMETHOD GetAnimVal(nsIDOMSVGAngle **aAnimVal)
{ return mVal->ToDOMAnimVal(aAnimVal, mSVGElement); }
};
#ifdef MOZ_SMIL
// We do not currently implemente a SMILAngle struct because in SVG 1.1 the
// only *animatable* attribute that takes an <angle> is 'orient', on the
// 'marker' element, and 'orient' must be special cased since it can also
// take the value 'auto', making it a more complex type.
struct SMILOrient : public nsISMILAttr
{
public:
SMILOrient(nsSVGOrientType* aOrientType,
nsSVGAngle* aAngle,
nsSVGElement* aSVGElement)
: mOrientType(aOrientType)
, mAngle(aAngle)
, 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.
nsSVGOrientType* mOrientType;
nsSVGAngle* mAngle;
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
};
nsresult

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

@ -1390,6 +1390,19 @@ nsSVGElement::DidChangeAngle(PRUint8 aAttrEnum, PRBool aDoSetAttr)
newStr, PR_TRUE);
}
void
nsSVGElement::DidAnimateAngle(PRUint8 aAttrEnum)
{
nsIFrame* frame = GetPrimaryFrame();
if (frame) {
AngleAttributesInfo info = GetAngleInfo();
frame->AttributeChanged(kNameSpaceID_None,
*info.mAngleInfo[aAttrEnum].mName,
nsIDOMMutationEvent::MODIFICATION);
}
}
nsSVGElement::BooleanAttributesInfo
nsSVGElement::GetBooleanInfo()
{
@ -1761,6 +1774,16 @@ nsSVGElement::GetAnimatedAttr(const nsIAtom* aName)
}
}
// Angles:
{
AngleAttributesInfo info = GetAngleInfo();
for (PRUint32 i = 0; i < info.mAngleCount; i++) {
if (aName == *info.mAngleInfo[i].mName) {
return info.mAngles[i].ToSMILAttr(this);
}
}
}
// preserveAspectRatio:
if (aName == nsGkAtoms::preserveAspectRatio) {
nsSVGPreserveAspectRatio *preserveAspectRatio = GetPreserveAspectRatio();

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

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

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

@ -217,6 +217,7 @@ NS_IMETHODIMP nsSVGMarkerElement::SetOrientToAngle(nsIDOMSVGAngle *angle)
float f;
angle->GetValue(&f);
NS_ENSURE_FINITE(f, NS_ERROR_DOM_SVG_WRONG_TYPE_ERR);
mAngleAttributes[ORIENT].SetBaseValue(f, this);
return NS_OK;
@ -379,19 +380,19 @@ nsSVGMarkerElement::GetPreserveAspectRatio()
gfxMatrix
nsSVGMarkerElement::GetMarkerTransform(float aStrokeWidth,
float aX, float aY, float aAngle)
float aX, float aY, float aAutoAngle)
{
float scale = 1.0;
if (mEnumAttributes[MARKERUNITS].GetAnimValue(this) ==
SVG_MARKERUNITS_STROKEWIDTH)
scale = aStrokeWidth;
if (mOrientType.GetAnimValue() != SVG_MARKER_ORIENT_AUTO) {
aAngle = mAngleAttributes[ORIENT].GetAnimValue();
}
float angle = mOrientType.GetAnimValue() == SVG_MARKER_ORIENT_AUTO ?
aAutoAngle :
mAngleAttributes[ORIENT].GetAnimValue() * M_PI / 180.0;
return gfxMatrix(cos(aAngle) * scale, sin(aAngle) * scale,
-sin(aAngle) * scale, cos(aAngle) * scale,
return gfxMatrix(cos(angle) * scale, sin(angle) * scale,
-sin(angle) * scale, cos(angle) * scale,
aX, aY);
}

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

@ -56,8 +56,13 @@ public:
nsresult SetBaseValue(PRUint16 aValue,
nsSVGElement *aSVGElement);
// XXX FIXME like https://bugzilla.mozilla.org/show_bug.cgi?id=545550 but
// without adding an mIsAnimated member...?
void SetBaseValue(PRUint16 aValue)
{ mAnimVal = mBaseVal = PRUint8(aValue); }
// no need to notify, since nsSVGAngle does that
void SetAnimValue(PRUint16 aValue)
{ mAnimVal = PRUint8(aValue); }
PRUint16 GetBaseValue() const
{ return mBaseVal; }
@ -132,11 +137,13 @@ public:
// public helpers
gfxMatrix GetMarkerTransform(float aStrokeWidth,
float aX, float aY, float aAngle);
float aX, float aY, float aAutoAngle);
gfxMatrix GetViewBoxTransform();
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
nsSVGOrientType* GetOrientType() { return &mOrientType; }
protected:
virtual PRBool ParseAttribute(PRInt32 aNameSpaceID, nsIAtom* aName,

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

@ -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(4, true)">
<title>Test animation of the "orient" attribute of the "marker" element</title>
<script xlink:href="smil-util.js" type="text/javascript"/>
<rect width="100%" height="100%" fill="lime"/>
<!-- Check that midway through the simple duration the orient attribute has
an animated value of -90deg -->
<marker id="marker_1" markerWidth="50" markerHeight="50"
markerUnits="userSpaceOnUse">
<rect width="20" height="20" fill="lime"/>
<animate attributeName="orient"
calcMode="linear"
begin="0s" dur="8s"
from="0deg" to="-180deg"
fill="freeze"/>
</marker>
<rect width="20" height="20" fill="red"/>
<line x2="0" y2="20" marker-end="url(#marker_1)" stroke="transparent"/>
<!-- Check that at the end of the simple duration the orient attribute has
an animated value of -90deg -->
<marker id="marker_2" markerWidth="50" markerHeight="50"
markerUnits="userSpaceOnUse">
<rect width="20" height="20" fill="lime"/>
<animate attributeName="orient"
calcMode="linear"
begin="0s" dur="4s"
from="0deg" to="-90deg"
fill="freeze"/>
</marker>
<rect x="20" width="20" height="20" fill="red"/>
<line x2="20" y2="20" marker-end="url(#marker_2)" stroke="transparent"/>
</svg>

После

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

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

@ -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 <angle> attributes:
== anim-marker-orient-01.svg lime.svg
# animate some enumeration attributes:
== anim-feComposite-operator-01.svg lime.svg
== anim-filter-filterUnits-01.svg lime.svg

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

@ -114,7 +114,7 @@ nsSVGMarkerFrame::GetCanvasTM()
gfxMatrix markedTM = mMarkedFrame->GetCanvasTM();
mInUse2 = PR_FALSE;
gfxMatrix markerTM = content->GetMarkerTransform(mStrokeWidth, mX, mY, mAngle);
gfxMatrix markerTM = content->GetMarkerTransform(mStrokeWidth, mX, mY, mAutoAngle);
gfxMatrix viewBoxTM = content->GetViewBoxTransform();
return viewBoxTM * markerTM * markedTM;
@ -158,7 +158,7 @@ nsSVGMarkerFrame::PaintMark(nsSVGRenderState *aContext,
mStrokeWidth = aStrokeWidth;
mX = aMark->x;
mY = aMark->y;
mAngle = aMark->angle;
mAutoAngle = aMark->angle;
gfxContext *gfx = aContext->GetGfxContext();
@ -202,7 +202,7 @@ nsSVGMarkerFrame::RegionMark(nsSVGPathGeometryFrame *aMarkedFrame,
mStrokeWidth = aStrokeWidth;
mX = aMark->x;
mY = aMark->y;
mAngle = aMark->angle;
mAutoAngle = aMark->angle;
// Force children to update their covered region
for (nsIFrame* kid = mFrames.FirstChild();

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

@ -98,7 +98,7 @@ public:
private:
// stuff needed for callback
nsSVGPathGeometryFrame *mMarkedFrame;
float mStrokeWidth, mX, mY, mAngle;
float mStrokeWidth, mX, mY, mAutoAngle;
// nsSVGContainerFrame methods:
virtual gfxMatrix GetCanvasTM();