зеркало из https://github.com/mozilla/gecko-dev.git
Bug 545042. Add support for SMIL animation of <angle> attributes in SVG. r=dholbert
This commit is contained in:
Родитель
5291f401f2
Коммит
ecd0d20033
|
@ -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();
|
||||
|
|
Загрузка…
Ссылка в новой задаче