mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 19:35:51 +00:00
Bug 436418, patch E: SVG/SMIL animateMotion - add support for <animateMotion> element and its core logic. r=roc
This commit is contained in:
parent
9907d2d6ff
commit
ea5825f520
@ -1281,6 +1281,7 @@ GK_ATOM(accumulate, "accumulate")
|
|||||||
GK_ATOM(additive, "additive")
|
GK_ATOM(additive, "additive")
|
||||||
GK_ATOM(attributeName, "attributeName")
|
GK_ATOM(attributeName, "attributeName")
|
||||||
GK_ATOM(attributeType, "attributeType")
|
GK_ATOM(attributeType, "attributeType")
|
||||||
|
GK_ATOM(auto_reverse, "auto-reverse")
|
||||||
GK_ATOM(begin, "begin")
|
GK_ATOM(begin, "begin")
|
||||||
GK_ATOM(by, "by")
|
GK_ATOM(by, "by")
|
||||||
GK_ATOM(calcMode, "calcMode")
|
GK_ATOM(calcMode, "calcMode")
|
||||||
@ -1288,6 +1289,7 @@ GK_ATOM(css, "CSS")
|
|||||||
GK_ATOM(dur, "dur")
|
GK_ATOM(dur, "dur")
|
||||||
GK_ATOM(keySplines, "keySplines")
|
GK_ATOM(keySplines, "keySplines")
|
||||||
GK_ATOM(keyTimes, "keyTimes")
|
GK_ATOM(keyTimes, "keyTimes")
|
||||||
|
GK_ATOM(mozAnimateMotionDummyAttr, "_mozAnimateMotionDummyAttr")
|
||||||
GK_ATOM(repeatCount, "repeatCount")
|
GK_ATOM(repeatCount, "repeatCount")
|
||||||
GK_ATOM(repeatDur, "repeatDur")
|
GK_ATOM(repeatDur, "repeatDur")
|
||||||
GK_ATOM(restart, "restart")
|
GK_ATOM(restart, "restart")
|
||||||
|
@ -91,6 +91,7 @@ endif # ENABLE_TESTS
|
|||||||
EXPORTS += \
|
EXPORTS += \
|
||||||
nsISMILAnimationElement.h \
|
nsISMILAnimationElement.h \
|
||||||
nsISMILAttr.h \
|
nsISMILAttr.h \
|
||||||
|
nsISMILType.h \
|
||||||
nsSMILAnimationController.h \
|
nsSMILAnimationController.h \
|
||||||
nsSMILCompositorTable.h \
|
nsSMILCompositorTable.h \
|
||||||
nsSMILCSSProperty.h \
|
nsSMILCSSProperty.h \
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
class nsSMILValue;
|
class nsSMILValue;
|
||||||
class nsISMILType;
|
class nsISMILType;
|
||||||
class nsISMILAnimationElement;
|
class nsISMILAnimationElement;
|
||||||
|
class nsIContent;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
// nsISMILAttr: A variable targeted by SMIL for animation and can therefore have
|
// nsISMILAttr: A variable targeted by SMIL for animation and can therefore have
|
||||||
@ -103,10 +104,20 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual nsresult SetAnimValue(const nsSMILValue& aValue) = 0;
|
virtual nsresult SetAnimValue(const nsSMILValue& aValue) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the targeted content node, for any nsISMILAttr implementations
|
||||||
|
* that want to expose that to the animation logic. Otherwise, returns
|
||||||
|
* null.
|
||||||
|
*
|
||||||
|
* @return the targeted content node, if this nsISMILAttr implementation
|
||||||
|
* wishes to make it avaiable. Otherwise, nsnull.
|
||||||
|
*/
|
||||||
|
virtual const nsIContent* GetTargetNode() const { return nsnull; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Virtual destructor, to make sure subclasses can clean themselves up.
|
* Virtual destructor, to make sure subclasses can clean themselves up.
|
||||||
*/
|
*/
|
||||||
virtual ~nsISMILAttr() {};
|
virtual ~nsISMILAttr() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NS_ISMILATTR_H_
|
#endif // NS_ISMILATTR_H_
|
||||||
|
@ -255,7 +255,7 @@ nsSMILAnimationFunction::ComposeResult(const nsISMILAttr& aSMILAttr,
|
|||||||
} else if (mLastValue) {
|
} else if (mLastValue) {
|
||||||
|
|
||||||
// Sampling last value
|
// Sampling last value
|
||||||
nsSMILValue last(values[values.Length() - 1]);
|
const nsSMILValue& last = values[values.Length() - 1];
|
||||||
result = last;
|
result = last;
|
||||||
|
|
||||||
// See comment in AccumulateResult: to-animation does not accumulate
|
// See comment in AccumulateResult: to-animation does not accumulate
|
||||||
|
@ -322,8 +322,10 @@ protected:
|
|||||||
|
|
||||||
PRBool ParseAttr(nsIAtom* aAttName, const nsISMILAttr& aSMILAttr,
|
PRBool ParseAttr(nsIAtom* aAttName, const nsISMILAttr& aSMILAttr,
|
||||||
nsSMILValue& aResult, PRBool& aCanCacheSoFar) const;
|
nsSMILValue& aResult, PRBool& aCanCacheSoFar) const;
|
||||||
nsresult GetValues(const nsISMILAttr& aSMILAttr,
|
|
||||||
nsSMILValueArray& aResult);
|
virtual nsresult GetValues(const nsISMILAttr& aSMILAttr,
|
||||||
|
nsSMILValueArray& aResult);
|
||||||
|
|
||||||
void CheckKeyTimes(PRUint32 aNumValues);
|
void CheckKeyTimes(PRUint32 aNumValues);
|
||||||
void CheckKeySplines(PRUint32 aNumValues);
|
void CheckKeySplines(PRUint32 aNumValues);
|
||||||
|
|
||||||
|
@ -132,6 +132,10 @@ CPPSRCS += nsSVGAnimateElement.cpp \
|
|||||||
nsSVGSetElement.cpp \
|
nsSVGSetElement.cpp \
|
||||||
nsSVGTransformSMILType.cpp \
|
nsSVGTransformSMILType.cpp \
|
||||||
nsSVGTransformSMILAttr.cpp \
|
nsSVGTransformSMILAttr.cpp \
|
||||||
|
SVGMotionSMILType.cpp \
|
||||||
|
SVGMotionSMILAttr.cpp \
|
||||||
|
SVGMotionSMILAnimationFunction.cpp \
|
||||||
|
SVGMotionSMILPathUtils.cpp \
|
||||||
SVGOrientSMILType.cpp \
|
SVGOrientSMILType.cpp \
|
||||||
SVGViewBoxSMILType.cpp \
|
SVGViewBoxSMILType.cpp \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
335
content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
Normal file
335
content/svg/content/src/SVGMotionSMILAnimationFunction.cpp
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
/* -*- 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 Foundation.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Daniel Holbert <dholbert@mozilla.com>
|
||||||
|
*
|
||||||
|
* 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 "SVGMotionSMILAnimationFunction.h"
|
||||||
|
#include "nsSMILParserUtils.h"
|
||||||
|
#include "nsSVGAngle.h"
|
||||||
|
#include "SVGMotionSMILType.h"
|
||||||
|
#include "SVGMotionSMILPathUtils.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
SVGMotionSMILAnimationFunction::SVGMotionSMILAnimationFunction()
|
||||||
|
: mRotateType(eRotateType_Explicit),
|
||||||
|
mRotateAngle(0.0f),
|
||||||
|
mPathSourceType(ePathSourceType_None),
|
||||||
|
mIsPathStale(PR_TRUE) // Try to initialize path on first GetValues call
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SVGMotionSMILAnimationFunction::MarkStaleIfAttributeAffectsPath(nsIAtom* aAttribute)
|
||||||
|
{
|
||||||
|
PRBool isAffected;
|
||||||
|
if (aAttribute == nsGkAtoms::path) {
|
||||||
|
isAffected = (mPathSourceType <= ePathSourceType_PathAttr);
|
||||||
|
} else if (aAttribute == nsGkAtoms::values) {
|
||||||
|
isAffected = (mPathSourceType <= ePathSourceType_ValuesAttr);
|
||||||
|
} else if (aAttribute == nsGkAtoms::from ||
|
||||||
|
aAttribute == nsGkAtoms::to) {
|
||||||
|
isAffected = (mPathSourceType <= ePathSourceType_ToAttr);
|
||||||
|
} else if (aAttribute == nsGkAtoms::by) {
|
||||||
|
isAffected = (mPathSourceType <= ePathSourceType_ByAttr);
|
||||||
|
} else {
|
||||||
|
NS_NOTREACHED("Should only call this method for path-describing attrs");
|
||||||
|
isAffected = PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAffected) {
|
||||||
|
mIsPathStale = PR_TRUE;
|
||||||
|
mHasChanged = PR_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PRBool
|
||||||
|
SVGMotionSMILAnimationFunction::SetAttr(nsIAtom* aAttribute,
|
||||||
|
const nsAString& aValue,
|
||||||
|
nsAttrValue& aResult,
|
||||||
|
nsresult* aParseResult)
|
||||||
|
{
|
||||||
|
if (aAttribute == nsGkAtoms::rotate) {
|
||||||
|
nsresult rv = SetRotate(aValue, aResult);
|
||||||
|
if (aParseResult) {
|
||||||
|
*aParseResult = rv;
|
||||||
|
}
|
||||||
|
} else if (aAttribute == nsGkAtoms::by ||
|
||||||
|
aAttribute == nsGkAtoms::from ||
|
||||||
|
aAttribute == nsGkAtoms::to ||
|
||||||
|
aAttribute == nsGkAtoms::values) {
|
||||||
|
MarkStaleIfAttributeAffectsPath(aAttribute);
|
||||||
|
} else {
|
||||||
|
// Defer to superclass method
|
||||||
|
return nsSMILAnimationFunction::SetAttr(aAttribute, aValue,
|
||||||
|
aResult, aParseResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRBool
|
||||||
|
SVGMotionSMILAnimationFunction::UnsetAttr(nsIAtom* aAttribute)
|
||||||
|
{
|
||||||
|
if (aAttribute == nsGkAtoms::rotate) {
|
||||||
|
UnsetRotate();
|
||||||
|
} else if (aAttribute == nsGkAtoms::by ||
|
||||||
|
aAttribute == nsGkAtoms::from ||
|
||||||
|
aAttribute == nsGkAtoms::to ||
|
||||||
|
aAttribute == nsGkAtoms::values) {
|
||||||
|
MarkStaleIfAttributeAffectsPath(aAttribute);
|
||||||
|
} else {
|
||||||
|
// Defer to superclass method
|
||||||
|
return nsSMILAnimationFunction::UnsetAttr(aAttribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsSMILAnimationFunction::nsSMILCalcMode
|
||||||
|
SVGMotionSMILAnimationFunction::GetCalcMode() const
|
||||||
|
{
|
||||||
|
const nsAttrValue* value = GetAttr(nsGkAtoms::calcMode);
|
||||||
|
if (!value) {
|
||||||
|
return CALC_PACED; // animateMotion defaults to calcMode="paced"
|
||||||
|
}
|
||||||
|
|
||||||
|
return nsSMILCalcMode(value->GetEnumValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Helpers for GetValues
|
||||||
|
|
||||||
|
void
|
||||||
|
SVGMotionSMILAnimationFunction::
|
||||||
|
RebuildPathAndVerticesFromBasicAttrs(const nsIContent* aContextElem)
|
||||||
|
{
|
||||||
|
NS_ABORT_IF_FALSE(!mPath, "regenerating when we aleady have path");
|
||||||
|
NS_ABORT_IF_FALSE(mPathVertices.IsEmpty(),
|
||||||
|
"regenerating when we already have vertices");
|
||||||
|
|
||||||
|
if (aContextElem->GetNameSpaceID() != kNameSpaceID_SVG) {
|
||||||
|
NS_ERROR("Uh oh, SVG animateMotion element targeting a non-SVG node");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: We have to cast away constness on context node, since the
|
||||||
|
// nsSVGLength2 methods that need it for unit-conversion
|
||||||
|
// (e.g. nsSVGLength2::GetBaseValue) aren't const-correct.
|
||||||
|
nsSVGElement* svgCtx =
|
||||||
|
static_cast<nsSVGElement*>(const_cast<nsIContent*>(aContextElem));
|
||||||
|
SVGMotionSMILPathUtils::PathGenerator pathGenerator(svgCtx);
|
||||||
|
|
||||||
|
PRBool success = PR_FALSE;
|
||||||
|
if (HasAttr(nsGkAtoms::values)) {
|
||||||
|
// Generate path based on our values array
|
||||||
|
mPathSourceType = ePathSourceType_ValuesAttr;
|
||||||
|
const nsAString& valuesStr = GetAttr(nsGkAtoms::values)->GetStringValue();
|
||||||
|
SVGMotionSMILPathUtils::MotionValueParser parser(&pathGenerator,
|
||||||
|
&mPathVertices);
|
||||||
|
success =
|
||||||
|
NS_SUCCEEDED(nsSMILParserUtils::ParseValuesGeneric(valuesStr, parser));
|
||||||
|
} else if (HasAttr(nsGkAtoms::to) || HasAttr(nsGkAtoms::by)) {
|
||||||
|
// Apply 'from' value (or a dummy 0,0 'from' value)
|
||||||
|
if (HasAttr(nsGkAtoms::from)) {
|
||||||
|
const nsAString& fromStr = GetAttr(nsGkAtoms::from)->GetStringValue();
|
||||||
|
success = pathGenerator.MoveToAbsolute(fromStr);
|
||||||
|
mPathVertices.AppendElement(0.0);
|
||||||
|
} else {
|
||||||
|
// Create dummy 'from' value at 0,0, if we're doing by-animation.
|
||||||
|
// (NOTE: We don't add the dummy 0-point to our list for *to-animation*,
|
||||||
|
// because the nsSMILAnimationFunction logic for to-animation doesn't
|
||||||
|
// expect a dummy value. It only expects one value: the final 'to' value.)
|
||||||
|
pathGenerator.MoveToOrigin();
|
||||||
|
if (!HasAttr(nsGkAtoms::to)) {
|
||||||
|
mPathVertices.AppendElement(0.0);
|
||||||
|
}
|
||||||
|
success = PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply 'to' or 'by' value
|
||||||
|
if (success) {
|
||||||
|
double dist;
|
||||||
|
if (HasAttr(nsGkAtoms::to)) {
|
||||||
|
mPathSourceType = ePathSourceType_ToAttr;
|
||||||
|
const nsAString& toStr = GetAttr(nsGkAtoms::to)->GetStringValue();
|
||||||
|
success = pathGenerator.LineToAbsolute(toStr, dist);
|
||||||
|
} else { // HasAttr(nsGkAtoms::by)
|
||||||
|
mPathSourceType = ePathSourceType_ByAttr;
|
||||||
|
const nsAString& byStr = GetAttr(nsGkAtoms::by)->GetStringValue();
|
||||||
|
success = pathGenerator.LineToRelative(byStr, dist);
|
||||||
|
}
|
||||||
|
if (success) {
|
||||||
|
mPathVertices.AppendElement(dist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (success) {
|
||||||
|
mPath = pathGenerator.GetResultingPath();
|
||||||
|
} else {
|
||||||
|
// Parse failure. Leave path as null, and clear path-related member data.
|
||||||
|
mPathVertices.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper to regenerate our path representation & its list of vertices
|
||||||
|
void
|
||||||
|
SVGMotionSMILAnimationFunction::
|
||||||
|
RebuildPathAndVertices(const nsIContent* aTargetElement)
|
||||||
|
{
|
||||||
|
NS_ABORT_IF_FALSE(mIsPathStale, "rebuilding path when it isn't stale");
|
||||||
|
|
||||||
|
// Clear stale data
|
||||||
|
mPath = nsnull;
|
||||||
|
mPathVertices.Clear();
|
||||||
|
mPathSourceType = ePathSourceType_None;
|
||||||
|
|
||||||
|
// Do we have a mpath child? if so, it trumps everything. Otherwise, we look
|
||||||
|
// through our list of path-defining attributes, in order of priority.
|
||||||
|
// XXXdholbert This is where we should check for mpath, in <mpath> patch.
|
||||||
|
// ...else, if no mpath child:
|
||||||
|
// XXXdholbert This is where we should check for path attr, in |path| patch.
|
||||||
|
// ...else {
|
||||||
|
{
|
||||||
|
// Get path & vertices from basic SMIL attrs: from/by/to/values
|
||||||
|
|
||||||
|
RebuildPathAndVerticesFromBasicAttrs(aTargetElement);
|
||||||
|
mValueNeedsReparsingEverySample = PR_TRUE;
|
||||||
|
}
|
||||||
|
mIsPathStale = PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRBool
|
||||||
|
SVGMotionSMILAnimationFunction::
|
||||||
|
GenerateValuesForPathAndPoints(gfxFlattenedPath* aPath,
|
||||||
|
nsTArray<double>& aPointDistances,
|
||||||
|
nsTArray<nsSMILValue>& aResult)
|
||||||
|
{
|
||||||
|
NS_ABORT_IF_FALSE(aResult.IsEmpty(), "outparam is non-empty");
|
||||||
|
|
||||||
|
const PRUint32 numPoints = aPointDistances.Length();
|
||||||
|
for (PRUint32 i = 0; i < numPoints; ++i) {
|
||||||
|
double curDist = aPointDistances[i];
|
||||||
|
if (!aResult.AppendElement(
|
||||||
|
SVGMotionSMILType::ConstructSMILValue(aPath, curDist,
|
||||||
|
mRotateType, mRotateAngle))) {
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
SVGMotionSMILAnimationFunction::GetValues(const nsISMILAttr& aSMILAttr,
|
||||||
|
nsSMILValueArray& aResult)
|
||||||
|
{
|
||||||
|
if (mIsPathStale) {
|
||||||
|
RebuildPathAndVertices(aSMILAttr.GetTargetNode());
|
||||||
|
}
|
||||||
|
NS_ABORT_IF_FALSE(!mIsPathStale, "Forgot to clear 'is path stale' state");
|
||||||
|
|
||||||
|
if (!mPath) {
|
||||||
|
// This could be due to e.g. a parse error.
|
||||||
|
NS_ABORT_IF_FALSE(mPathVertices.IsEmpty(), "have vertices but no path");
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
NS_ABORT_IF_FALSE(!mPathVertices.IsEmpty(), "have a path but no vertices");
|
||||||
|
|
||||||
|
// Now: Make the actual list of nsSMILValues
|
||||||
|
PRBool success = GenerateValuesForPathAndPoints(mPath, mPathVertices,
|
||||||
|
aResult);
|
||||||
|
if (!success) {
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
SVGMotionSMILAnimationFunction::SetRotate(const nsAString& aRotate,
|
||||||
|
nsAttrValue& aResult)
|
||||||
|
{
|
||||||
|
mHasChanged = PR_TRUE;
|
||||||
|
|
||||||
|
aResult.SetTo(aRotate);
|
||||||
|
if (aRotate.EqualsLiteral("auto")) {
|
||||||
|
mRotateType = eRotateType_Auto;
|
||||||
|
} else if (aRotate.EqualsLiteral("auto-reverse")) {
|
||||||
|
mRotateType = eRotateType_AutoReverse;
|
||||||
|
} else {
|
||||||
|
mRotateType = eRotateType_Explicit;
|
||||||
|
|
||||||
|
// Parse numeric angle string, with the help of a temp nsSVGAngle.
|
||||||
|
nsSVGAngle svgAngle;
|
||||||
|
svgAngle.Init();
|
||||||
|
nsresult rv = svgAngle.SetBaseValueString(aRotate, nsnull, PR_FALSE);
|
||||||
|
if (NS_FAILED(rv)) { // Parse error
|
||||||
|
mRotateAngle = 0.0f; // set default rotate angle
|
||||||
|
// XXX report to console?
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
mRotateAngle = svgAngle.GetBaseValInSpecifiedUnits();
|
||||||
|
|
||||||
|
// Convert to radian units, if we're not already in radians.
|
||||||
|
PRUint8 angleUnit = svgAngle.GetBaseValueUnit();
|
||||||
|
if (angleUnit != nsIDOMSVGAngle::SVG_ANGLETYPE_RAD) {
|
||||||
|
mRotateAngle *= nsSVGAngle::GetDegreesPerUnit(angleUnit) /
|
||||||
|
nsSVGAngle::GetDegreesPerUnit(nsIDOMSVGAngle::SVG_ANGLETYPE_RAD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SVGMotionSMILAnimationFunction::UnsetRotate()
|
||||||
|
{
|
||||||
|
mRotateAngle = 0.0f; // default value
|
||||||
|
mRotateType = eRotateType_Explicit;
|
||||||
|
mHasChanged = PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRBool
|
||||||
|
SVGMotionSMILAnimationFunction::TreatSingleValueAsStatic() const
|
||||||
|
{
|
||||||
|
// <animateMotion> has two more ways that we could be just sampling a single
|
||||||
|
// value -- via path attribute and the <mpath> element, with a path
|
||||||
|
// description that just includes a single "move" command.
|
||||||
|
return (mPathSourceType == ePathSourceType_ValuesAttr ||
|
||||||
|
mPathSourceType == ePathSourceType_PathAttr ||
|
||||||
|
mPathSourceType == ePathSourceType_Mpath);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mozilla
|
106
content/svg/content/src/SVGMotionSMILAnimationFunction.h
Normal file
106
content/svg/content/src/SVGMotionSMILAnimationFunction.h
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/* -*- 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 Foundation
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Daniel Holbert <dholbert@mozilla.com>
|
||||||
|
*
|
||||||
|
* 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_SVGMOTIONSMILANIMATIONFUNCTION_H_
|
||||||
|
#define MOZILLA_SVGMOTIONSMILANIMATIONFUNCTION_H_
|
||||||
|
|
||||||
|
#include "nsSMILAnimationFunction.h"
|
||||||
|
#include "SVGMotionSMILType.h" // for RotateType
|
||||||
|
#include "gfxPath.h" // for gfxFlattenedPath
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// SVGMotionSMILAnimationFunction
|
||||||
|
//
|
||||||
|
// Subclass of nsSMILAnimationFunction to support a few extra features offered
|
||||||
|
// by the <animateMotion> element.
|
||||||
|
//
|
||||||
|
class SVGMotionSMILAnimationFunction : public nsSMILAnimationFunction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SVGMotionSMILAnimationFunction();
|
||||||
|
NS_OVERRIDE virtual PRBool SetAttr(nsIAtom* aAttribute,
|
||||||
|
const nsAString& aValue,
|
||||||
|
nsAttrValue& aResult,
|
||||||
|
nsresult* aParseResult = nsnull);
|
||||||
|
NS_OVERRIDE virtual PRBool UnsetAttr(nsIAtom* aAttribute);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
enum PathSourceType {
|
||||||
|
// NOTE: Ordering matters here. Higher-priority path-descriptors should
|
||||||
|
// have higher enumerated values
|
||||||
|
ePathSourceType_None, // uninitialized or not applicable
|
||||||
|
ePathSourceType_ByAttr, // by or from-by animation
|
||||||
|
ePathSourceType_ToAttr, // to or from-to animation
|
||||||
|
ePathSourceType_ValuesAttr,
|
||||||
|
ePathSourceType_PathAttr,
|
||||||
|
ePathSourceType_Mpath
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_OVERRIDE virtual nsSMILCalcMode GetCalcMode() const;
|
||||||
|
NS_OVERRIDE virtual nsresult GetValues(const nsISMILAttr& aSMILAttr,
|
||||||
|
nsSMILValueArray& aResult);
|
||||||
|
NS_OVERRIDE virtual PRBool TreatSingleValueAsStatic() const;
|
||||||
|
|
||||||
|
nsresult SetRotate(const nsAString& aRotate, nsAttrValue& aResult);
|
||||||
|
void UnsetRotate();
|
||||||
|
|
||||||
|
// Helpers for GetValues
|
||||||
|
void MarkStaleIfAttributeAffectsPath(nsIAtom* aAttribute);
|
||||||
|
nsresult SetPathVerticesFromPathString(const nsAString& aPathSpec);
|
||||||
|
void RebuildPathAndVertices(const nsIContent* aContextElem);
|
||||||
|
void RebuildPathAndVerticesFromBasicAttrs(const nsIContent* aContextElem);
|
||||||
|
PRBool GenerateValuesForPathAndPoints(gfxFlattenedPath* aPath,
|
||||||
|
nsTArray<double>& aPointDistances,
|
||||||
|
nsTArray<nsSMILValue>& aResult);
|
||||||
|
|
||||||
|
// Members
|
||||||
|
// -------
|
||||||
|
RotateType mRotateType; // auto, auto-reverse, or explicit.
|
||||||
|
float mRotateAngle; // the angle value, if explicit.
|
||||||
|
|
||||||
|
PathSourceType mPathSourceType; // source of our gfxFlattenedPath.
|
||||||
|
nsRefPtr<gfxFlattenedPath> mPath; // representation of motion path.
|
||||||
|
nsTArray<double> mPathVertices; // distances of vertices along path.
|
||||||
|
|
||||||
|
PRPackedBool mIsPathStale;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // MOZILLA_SVGMOTIONSMILANIMATIONFUNCTION_H_
|
90
content/svg/content/src/SVGMotionSMILAttr.cpp
Normal file
90
content/svg/content/src/SVGMotionSMILAttr.cpp
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/* -*- 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) 2010
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Daniel Holbert <dholbert@mozilla.com>
|
||||||
|
*
|
||||||
|
* 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 ***** */
|
||||||
|
|
||||||
|
/* representation of a dummy attribute targeted by <animateMotion> element */
|
||||||
|
|
||||||
|
#include "SVGMotionSMILAttr.h"
|
||||||
|
#include "SVGMotionSMILType.h"
|
||||||
|
#include "nsISMILAnimationElement.h"
|
||||||
|
#include "nsSMILValue.h"
|
||||||
|
#include "nsAttrValue.h"
|
||||||
|
#include "nsGkAtoms.h"
|
||||||
|
#include "nsDebug.h"
|
||||||
|
#include "nsCRT.h"
|
||||||
|
#include "nsSVGLength2.h"
|
||||||
|
#include "nsSMILParserUtils.h"
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
SVGMotionSMILAttr::ValueFromString(const nsAString& aStr,
|
||||||
|
const nsISMILAnimationElement* aSrcElement,
|
||||||
|
nsSMILValue& aValue,
|
||||||
|
PRBool& aCanCache) const
|
||||||
|
{
|
||||||
|
NS_NOTREACHED("Shouldn't using nsISMILAttr::ValueFromString for parsing "
|
||||||
|
"animateMotion's SMIL values.");
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsSMILValue
|
||||||
|
SVGMotionSMILAttr::GetBaseValue() const
|
||||||
|
{
|
||||||
|
return nsSMILValue(&SVGMotionSMILType::sSingleton);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SVGMotionSMILAttr::ClearAnimValue()
|
||||||
|
{
|
||||||
|
mSVGElement->SetAnimateMotionTransform(nsnull);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
SVGMotionSMILAttr::SetAnimValue(const nsSMILValue& aValue)
|
||||||
|
{
|
||||||
|
gfxMatrix matrix = SVGMotionSMILType::CreateMatrix(aValue);
|
||||||
|
mSVGElement->SetAnimateMotionTransform(&matrix);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nsIContent*
|
||||||
|
SVGMotionSMILAttr::GetTargetNode() const
|
||||||
|
{
|
||||||
|
return mSVGElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mozilla
|
80
content/svg/content/src/SVGMotionSMILAttr.h
Normal file
80
content/svg/content/src/SVGMotionSMILAttr.h
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/* -*- 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) 2010
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Daniel Holbert <dholbert@mozilla.com>
|
||||||
|
*
|
||||||
|
* 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 ***** */
|
||||||
|
|
||||||
|
/* representation of a dummy attribute targeted by <animateMotion> element */
|
||||||
|
|
||||||
|
#ifndef MOZILLA_SVGMOTIONSMILATTR_H_
|
||||||
|
#define MOZILLA_SVGMOTIONSMILATTR_H_
|
||||||
|
|
||||||
|
#include "nsISMILAttr.h"
|
||||||
|
class nsSVGElement;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SVGMotionSMILAttr: Implements the nsISMILAttr interface for SMIL animations
|
||||||
|
* from <animateMotion>.
|
||||||
|
*
|
||||||
|
* NOTE: Even though there's technically no "motion" attribute, we behave in
|
||||||
|
* many ways as if there were, for simplicity.
|
||||||
|
*/
|
||||||
|
class SVGMotionSMILAttr : public nsISMILAttr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SVGMotionSMILAttr(nsSVGElement* aSVGElement)
|
||||||
|
: mSVGElement(aSVGElement) {}
|
||||||
|
|
||||||
|
// nsISMILAttr methods
|
||||||
|
virtual nsresult ValueFromString(const nsAString& aStr,
|
||||||
|
const nsISMILAnimationElement* aSrcElement,
|
||||||
|
nsSMILValue& aValue,
|
||||||
|
PRBool& aCanCache) const;
|
||||||
|
virtual nsSMILValue GetBaseValue() const;
|
||||||
|
virtual nsresult SetAnimValue(const nsSMILValue& aValue);
|
||||||
|
virtual void ClearAnimValue();
|
||||||
|
virtual const nsIContent* GetTargetNode() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Raw pointers are OK here because this SVGMotionSMILAttr is both
|
||||||
|
// created & destroyed during a SMIL sample-step, during which time the DOM
|
||||||
|
// isn't modified.
|
||||||
|
nsSVGElement* mSVGElement;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // MOZILLA_SVGMOTIONSMILATTR_H_
|
201
content/svg/content/src/SVGMotionSMILPathUtils.cpp
Normal file
201
content/svg/content/src/SVGMotionSMILPathUtils.cpp
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
/* -*- 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 Foundation.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Daniel Holbert <dholbert@mozilla.com>
|
||||||
|
*
|
||||||
|
* 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 "SVGMotionSMILPathUtils.h"
|
||||||
|
#include "nsSVGElement.h"
|
||||||
|
#include "nsSVGLength2.h"
|
||||||
|
#include "nsContentCreatorFunctions.h" // For NS_NewSVGElement
|
||||||
|
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// PathGenerator methods
|
||||||
|
|
||||||
|
// For the dummy 'from' value used in pure by-animation & to-animation
|
||||||
|
void
|
||||||
|
SVGMotionSMILPathUtils::PathGenerator::
|
||||||
|
MoveToOrigin()
|
||||||
|
{
|
||||||
|
NS_ABORT_IF_FALSE(!mHaveReceivedCommands,
|
||||||
|
"Not expecting requests for mid-path MoveTo commands");
|
||||||
|
mHaveReceivedCommands = PR_TRUE;
|
||||||
|
mGfxContext.MoveTo(gfxPoint(0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
// For 'from' and the first entry in 'values'.
|
||||||
|
PRBool
|
||||||
|
SVGMotionSMILPathUtils::PathGenerator::
|
||||||
|
MoveToAbsolute(const nsAString& aCoordPairStr)
|
||||||
|
{
|
||||||
|
NS_ABORT_IF_FALSE(!mHaveReceivedCommands,
|
||||||
|
"Not expecting requests for mid-path MoveTo commands");
|
||||||
|
mHaveReceivedCommands = PR_TRUE;
|
||||||
|
|
||||||
|
float xVal, yVal;
|
||||||
|
if (!ParseCoordinatePair(aCoordPairStr, xVal, yVal)) {
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
mGfxContext.MoveTo(gfxPoint(xVal, yVal));
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For 'to' and every entry in 'values' except the first.
|
||||||
|
PRBool
|
||||||
|
SVGMotionSMILPathUtils::PathGenerator::
|
||||||
|
LineToAbsolute(const nsAString& aCoordPairStr, double& aSegmentDistance)
|
||||||
|
{
|
||||||
|
mHaveReceivedCommands = PR_TRUE;
|
||||||
|
|
||||||
|
float xVal, yVal;
|
||||||
|
if (!ParseCoordinatePair(aCoordPairStr, xVal, yVal)) {
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
gfxPoint initialPoint = mGfxContext.CurrentPoint();
|
||||||
|
|
||||||
|
mGfxContext.LineTo(gfxPoint(xVal, yVal));
|
||||||
|
aSegmentDistance = NS_hypot(initialPoint.x - xVal, initialPoint.y -yVal);
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For 'by'.
|
||||||
|
PRBool
|
||||||
|
SVGMotionSMILPathUtils::PathGenerator::
|
||||||
|
LineToRelative(const nsAString& aCoordPairStr, double& aSegmentDistance)
|
||||||
|
{
|
||||||
|
mHaveReceivedCommands = PR_TRUE;
|
||||||
|
|
||||||
|
float xVal, yVal;
|
||||||
|
if (!ParseCoordinatePair(aCoordPairStr, xVal, yVal)) {
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
mGfxContext.LineTo(mGfxContext.CurrentPoint() + gfxPoint(xVal, yVal));
|
||||||
|
aSegmentDistance = NS_hypot(xVal, yVal);
|
||||||
|
return PR_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
already_AddRefed<gfxFlattenedPath>
|
||||||
|
SVGMotionSMILPathUtils::PathGenerator::GetResultingPath()
|
||||||
|
{
|
||||||
|
return mGfxContext.GetFlattenedPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// Helper / protected methods
|
||||||
|
|
||||||
|
static PRBool
|
||||||
|
ParseOneCoordinate(char** aRest, nsSVGLength2& aLengthVal)
|
||||||
|
{
|
||||||
|
aLengthVal.Init();
|
||||||
|
|
||||||
|
// Grab token, up to next delimiter
|
||||||
|
// XXXdholbert Ideally we'd like to know if the delimeter we found was a
|
||||||
|
// comma (and if so, fail if we come across any more commas before the next
|
||||||
|
// value). Current behavior will accept mutliple commas in between values,
|
||||||
|
// and that's not technically spec-correct, but it's simpler and it matches
|
||||||
|
// our behavior elsewhere where we use strtok with SVG_COMMA_WSP_DELIM.
|
||||||
|
char* token = nsCRT::strtok(*aRest, SVG_COMMA_WSP_DELIM, aRest);
|
||||||
|
if (!token) {
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse token into value + unit
|
||||||
|
nsresult rv = aLengthVal.SetBaseValueString(NS_ConvertASCIItoUTF16(token),
|
||||||
|
nsnull, PR_FALSE);
|
||||||
|
return NS_SUCCEEDED(rv);
|
||||||
|
}
|
||||||
|
|
||||||
|
PRBool
|
||||||
|
SVGMotionSMILPathUtils::PathGenerator::
|
||||||
|
ParseCoordinatePair(const nsAString& aCoordPairStr,
|
||||||
|
float& aXVal, float& aYVal)
|
||||||
|
{
|
||||||
|
nsSVGLength2 xLength, yLength;
|
||||||
|
|
||||||
|
char* str = ToNewCString(aCoordPairStr);
|
||||||
|
char* rest = str;
|
||||||
|
PRBool success = PR_FALSE;
|
||||||
|
|
||||||
|
if (ParseOneCoordinate(&rest, xLength) &&
|
||||||
|
ParseOneCoordinate(&rest, yLength)) {
|
||||||
|
|
||||||
|
// Check for any non-whitespace characters remaining at the end.
|
||||||
|
PRBool foundTrailingNonWhitespace = PR_FALSE;
|
||||||
|
while (*rest != '\0') {
|
||||||
|
if (!IsSVGWhitespace(*rest)) {
|
||||||
|
foundTrailingNonWhitespace = PR_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!foundTrailingNonWhitespace) {
|
||||||
|
success = PR_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nsMemory::Free(str);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
aXVal = xLength.GetBaseValue(mSVGElement);
|
||||||
|
aYVal = yLength.GetBaseValue(mSVGElement);
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------
|
||||||
|
// MotionValueParser methods
|
||||||
|
nsresult
|
||||||
|
SVGMotionSMILPathUtils::MotionValueParser::
|
||||||
|
Parse(const nsAString& aValueStr)
|
||||||
|
{
|
||||||
|
PRBool success;
|
||||||
|
if (!mPathGenerator->HaveReceivedCommands()) {
|
||||||
|
// Interpret first value in "values" attribute as the path's initial MoveTo
|
||||||
|
success = mPathGenerator->MoveToAbsolute(aValueStr);
|
||||||
|
if (success) {
|
||||||
|
success = !!mPointDistances->AppendElement(0.0);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
double dist;
|
||||||
|
success = mPathGenerator->LineToAbsolute(aValueStr, dist);
|
||||||
|
if (success) {
|
||||||
|
mDistanceSoFar += dist;
|
||||||
|
success = !!mPointDistances->AppendElement(mDistanceSoFar);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success ? NS_OK : NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mozilla
|
129
content/svg/content/src/SVGMotionSMILPathUtils.h
Normal file
129
content/svg/content/src/SVGMotionSMILPathUtils.h
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
/* -*- 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 Foundation.
|
||||||
|
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Daniel Holbert <dholbert@mozilla.com>
|
||||||
|
*
|
||||||
|
* 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 ***** */
|
||||||
|
|
||||||
|
/* Helper class to help with generating anonymous path elements for
|
||||||
|
<animateMotion> elements to use. */
|
||||||
|
|
||||||
|
#ifndef MOZILLA_SVGMOTIONSMILPATHUTILS_H_
|
||||||
|
#define MOZILLA_SVGMOTIONSMILPATHUTILS_H_
|
||||||
|
|
||||||
|
#include "nsSMILParserUtils.h"
|
||||||
|
#include "nsAutoPtr.h"
|
||||||
|
#include "nsTArray.h"
|
||||||
|
#include "nsDebug.h"
|
||||||
|
#include "gfxContext.h"
|
||||||
|
#include "nsSVGUtils.h"
|
||||||
|
|
||||||
|
class nsSVGElement;
|
||||||
|
class nsIContent;
|
||||||
|
class nsIDocument;
|
||||||
|
class nsAString;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
class SVGMotionSMILPathUtils {
|
||||||
|
public:
|
||||||
|
// Class to assist in generating a gfxFlattenedPath, based on
|
||||||
|
// coordinates in the <animateMotion> from/by/to/values attributes.
|
||||||
|
class PathGenerator {
|
||||||
|
public:
|
||||||
|
PathGenerator(nsSVGElement* aSVGElement)
|
||||||
|
: mSVGElement(aSVGElement),
|
||||||
|
mGfxContext(nsSVGUtils::GetThebesComputationalSurface()),
|
||||||
|
mHaveReceivedCommands(PR_FALSE)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Methods for adding various path commands to output path.
|
||||||
|
// Note: aCoordPairStr is expected to be a whitespace and/or
|
||||||
|
// comma-separated x,y coordinate-pair -- see description of
|
||||||
|
// "the specified values for from, by, to, and values" at
|
||||||
|
// http://www.w3.org/TR/SVG11/animate.html#AnimateMotionElement
|
||||||
|
void MoveToOrigin();
|
||||||
|
PRBool MoveToAbsolute(const nsAString& aCoordPairStr);
|
||||||
|
PRBool LineToAbsolute(const nsAString& aCoordPairStr,
|
||||||
|
double& aSegmentDistance);
|
||||||
|
PRBool LineToRelative(const nsAString& aCoordPairStr,
|
||||||
|
double& aSegmentDistance);
|
||||||
|
|
||||||
|
// Accessor to let clients check if we've received any commands yet.
|
||||||
|
inline PRBool HaveReceivedCommands() { return mHaveReceivedCommands; }
|
||||||
|
// Accessor to get the finalized path
|
||||||
|
already_AddRefed<gfxFlattenedPath> GetResultingPath();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// Helper methods
|
||||||
|
PRBool ParseCoordinatePair(const nsAString& aStr,
|
||||||
|
float& aXVal, float& aYVal);
|
||||||
|
|
||||||
|
PRBool AppendCommand(const nsACString& aCommandStr,
|
||||||
|
const nsAString& aCoordPairStr);
|
||||||
|
|
||||||
|
// Member data
|
||||||
|
nsSVGElement* mSVGElement; // context for converting out of relative units
|
||||||
|
gfxContext mGfxContext;
|
||||||
|
PRPackedBool mHaveReceivedCommands;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Class to assist in passing each subcomponent of a |values| attribute to
|
||||||
|
// a PathGenerator, for generating a corresponding gfxFlattenedPath.
|
||||||
|
class MotionValueParser : public nsSMILParserUtils::GenericValueParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MotionValueParser(PathGenerator* aPathGenerator,
|
||||||
|
nsTArray<double>* aPointDistances)
|
||||||
|
: mPathGenerator(aPathGenerator),
|
||||||
|
mPointDistances(aPointDistances),
|
||||||
|
mDistanceSoFar(0.0)
|
||||||
|
{
|
||||||
|
NS_ABORT_IF_FALSE(mPointDistances->IsEmpty(),
|
||||||
|
"expecting point distances array to start empty");
|
||||||
|
}
|
||||||
|
|
||||||
|
// nsSMILParserUtils::GenericValueParser interface
|
||||||
|
virtual nsresult Parse(const nsAString& aValueStr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
PathGenerator* mPathGenerator;
|
||||||
|
nsTArray<double>* mPointDistances;
|
||||||
|
double mDistanceSoFar;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // MOZILLA_SVGMOTIONSMILPATHUTILS_H_
|
523
content/svg/content/src/SVGMotionSMILType.cpp
Normal file
523
content/svg/content/src/SVGMotionSMILType.cpp
Normal file
@ -0,0 +1,523 @@
|
|||||||
|
/* -*- 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) 2010
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Daniel Holbert <dholbert@mozilla.com>
|
||||||
|
*
|
||||||
|
* 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 ***** */
|
||||||
|
|
||||||
|
/* implementation of nsISMILType for use by <animateMotion> element */
|
||||||
|
|
||||||
|
#include "SVGMotionSMILType.h"
|
||||||
|
#include "nsSMILValue.h"
|
||||||
|
#include "nsDebug.h"
|
||||||
|
#include "nsSVGTransform.h"
|
||||||
|
#include "nsSVGAngle.h"
|
||||||
|
#include "nsIDOMSVGAngle.h"
|
||||||
|
#include "nsSVGPathElement.h"
|
||||||
|
#include "nsSVGPathSeg.h"
|
||||||
|
#include "nsIDOMSVGPathSeg.h"
|
||||||
|
#include "nsIDOMSVGPathSegList.h"
|
||||||
|
#include "nsMathUtils.h"
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
/*static*/ SVGMotionSMILType SVGMotionSMILType::sSingleton;
|
||||||
|
|
||||||
|
|
||||||
|
// Helper enum, for distinguishing between types of MotionSegment structs
|
||||||
|
enum SegmentType {
|
||||||
|
eSegmentType_Translation,
|
||||||
|
eSegmentType_PathPoint
|
||||||
|
};
|
||||||
|
|
||||||
|
// Helper Structs: containers for params to define our MotionSegment
|
||||||
|
// (either simple translation or point-on-a-path)
|
||||||
|
struct TranslationParams { // Simple translation
|
||||||
|
float mX;
|
||||||
|
float mY;
|
||||||
|
};
|
||||||
|
struct PathPointParams { // Point along a path
|
||||||
|
gfxFlattenedPath* mPath; // NOTE: Refcounted; need to AddRef/Release.
|
||||||
|
float mDistToPoint; // Distance from path start to the point on the path that
|
||||||
|
// we're interested in.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper Struct: MotionSegment
|
||||||
|
*
|
||||||
|
* Instances of this class represent the points that we move between during
|
||||||
|
* <animateMotion>. Each nsSMILValue will get a nsTArray of these (generally
|
||||||
|
* with at most 1 entry in the array, except for in SandwichAdd). (This
|
||||||
|
* matches our behavior in nsSVGTransformSMILType.)
|
||||||
|
*
|
||||||
|
* NOTE: In general, MotionSegments are represented as points on a path
|
||||||
|
* (eSegmentType_PathPoint), so that we can easily interpolate and compute
|
||||||
|
* distance *along their path*. However, Add() outputs MotionSegments as
|
||||||
|
* simple translations (eSegmentType_Translation), because adding two points
|
||||||
|
* from a path (e.g. when accumulating a repeated animation) will generally
|
||||||
|
* take you to an arbitrary point *off* of the path.
|
||||||
|
*/
|
||||||
|
struct MotionSegment
|
||||||
|
{
|
||||||
|
// Default constructor just locks us into being a Translation, and leaves
|
||||||
|
// other fields uninitialized (since client is presumably about to set them)
|
||||||
|
MotionSegment()
|
||||||
|
: mSegmentType(eSegmentType_Translation)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
// Constructor for a translation
|
||||||
|
MotionSegment(float aX, float aY, float aRotateAngle)
|
||||||
|
: mRotateType(eRotateType_Explicit), mRotateAngle(aRotateAngle),
|
||||||
|
mSegmentType(eSegmentType_Translation)
|
||||||
|
{
|
||||||
|
mU.mTranslationParams.mX = aX;
|
||||||
|
mU.mTranslationParams.mY = aY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constructor for a point on a path (NOTE: AddRef's)
|
||||||
|
MotionSegment(gfxFlattenedPath* aPath, float aDistToPoint,
|
||||||
|
RotateType aRotateType, float aRotateAngle)
|
||||||
|
: mRotateType(aRotateType), mRotateAngle(aRotateAngle),
|
||||||
|
mSegmentType(eSegmentType_PathPoint)
|
||||||
|
{
|
||||||
|
mU.mPathPointParams.mPath = aPath;
|
||||||
|
mU.mPathPointParams.mDistToPoint = aDistToPoint;
|
||||||
|
|
||||||
|
NS_ADDREF(mU.mPathPointParams.mPath); // Retain a reference to path
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy constructor (NOTE: AddRef's if we're eSegmentType_PathPoint)
|
||||||
|
MotionSegment(const MotionSegment& aOther)
|
||||||
|
: mRotateType(aOther.mRotateType), mRotateAngle(aOther.mRotateAngle),
|
||||||
|
mSegmentType(aOther.mSegmentType)
|
||||||
|
{
|
||||||
|
if (mSegmentType == eSegmentType_Translation) {
|
||||||
|
mU.mTranslationParams = aOther.mU.mTranslationParams;
|
||||||
|
} else { // mSegmentType == eSegmentType_PathPoint
|
||||||
|
mU.mPathPointParams = aOther.mU.mPathPointParams;
|
||||||
|
NS_ADDREF(mU.mPathPointParams.mPath); // Retain a reference to path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destructor (releases any reference we were holding onto)
|
||||||
|
~MotionSegment()
|
||||||
|
{
|
||||||
|
if (mSegmentType == eSegmentType_PathPoint) {
|
||||||
|
NS_RELEASE(mU.mPathPointParams.mPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comparison operators
|
||||||
|
PRBool operator==(const MotionSegment& aOther) const
|
||||||
|
{
|
||||||
|
// Compare basic params
|
||||||
|
if (mSegmentType != aOther.mSegmentType ||
|
||||||
|
mRotateType != aOther.mRotateType ||
|
||||||
|
(mRotateType == eRotateType_Explicit && // Technically, angle mismatch
|
||||||
|
mRotateAngle != aOther.mRotateAngle)) { // only matters for Explicit.
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare translation params, if we're a translation.
|
||||||
|
if (mSegmentType == eSegmentType_Translation) {
|
||||||
|
return mU.mTranslationParams.mX == aOther.mU.mTranslationParams.mX &&
|
||||||
|
mU.mTranslationParams.mY == aOther.mU.mTranslationParams.mY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Else, compare path-point params, if we're a path point.
|
||||||
|
return (mU.mPathPointParams.mPath == aOther.mU.mPathPointParams.mPath) &&
|
||||||
|
(mU.mPathPointParams.mDistToPoint ==
|
||||||
|
aOther.mU.mPathPointParams.mDistToPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
PRBool operator!=(const MotionSegment& aOther) const
|
||||||
|
{
|
||||||
|
return !(*this == aOther);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Member Data
|
||||||
|
// -----------
|
||||||
|
RotateType mRotateType; // Explicit angle vs. auto vs. auto-reverse.
|
||||||
|
float mRotateAngle; // Only used if mRotateType == eRotateType_Explicit.
|
||||||
|
const SegmentType mSegmentType; // This determines how we interpret
|
||||||
|
// mU. (const for safety/sanity)
|
||||||
|
|
||||||
|
union { // Union to let us hold the params for either segment-type.
|
||||||
|
TranslationParams mTranslationParams;
|
||||||
|
PathPointParams mPathPointParams;
|
||||||
|
} mU;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef nsTArray<MotionSegment> MotionSegmentArray;
|
||||||
|
|
||||||
|
// Helper methods to cast nsSMILValue.mU.mPtr to the right pointer-type
|
||||||
|
static MotionSegmentArray&
|
||||||
|
ExtractMotionSegmentArray(nsSMILValue& aValue)
|
||||||
|
{
|
||||||
|
return *static_cast<MotionSegmentArray*>(aValue.mU.mPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MotionSegmentArray&
|
||||||
|
ExtractMotionSegmentArray(const nsSMILValue& aValue)
|
||||||
|
{
|
||||||
|
return *static_cast<const MotionSegmentArray*>(aValue.mU.mPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// nsISMILType Methods
|
||||||
|
// -------------------
|
||||||
|
|
||||||
|
void
|
||||||
|
SVGMotionSMILType::Init(nsSMILValue& aValue) const
|
||||||
|
{
|
||||||
|
NS_ABORT_IF_FALSE(aValue.IsNull(), "Unexpected SMIL type");
|
||||||
|
|
||||||
|
aValue.mType = this;
|
||||||
|
aValue.mU.mPtr = new MotionSegmentArray(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SVGMotionSMILType::Destroy(nsSMILValue& aValue) const
|
||||||
|
{
|
||||||
|
NS_ABORT_IF_FALSE(aValue.mType == this, "Unexpected SMIL type");
|
||||||
|
|
||||||
|
MotionSegmentArray* arr = static_cast<MotionSegmentArray*>(aValue.mU.mPtr);
|
||||||
|
delete arr;
|
||||||
|
|
||||||
|
aValue.mU.mPtr = nsnull;
|
||||||
|
aValue.mType = &nsSMILNullType::sSingleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
SVGMotionSMILType::Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const
|
||||||
|
{
|
||||||
|
NS_ABORT_IF_FALSE(aDest.mType == aSrc.mType, "Incompatible SMIL types");
|
||||||
|
NS_ABORT_IF_FALSE(aDest.mType == this, "Unexpected SMIL type");
|
||||||
|
|
||||||
|
const MotionSegmentArray& srcArr = ExtractMotionSegmentArray(aSrc);
|
||||||
|
MotionSegmentArray& dstArr = ExtractMotionSegmentArray(aDest);
|
||||||
|
|
||||||
|
// Ensure we have sufficient memory.
|
||||||
|
if (!dstArr.SetCapacity(srcArr.Length())) {
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
dstArr = srcArr; // Do the assignment.
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRBool
|
||||||
|
SVGMotionSMILType::IsEqual(const nsSMILValue& aLeft,
|
||||||
|
const nsSMILValue& aRight) const
|
||||||
|
{
|
||||||
|
NS_ABORT_IF_FALSE(aLeft.mType == aRight.mType, "Incompatible SMIL types");
|
||||||
|
NS_ABORT_IF_FALSE(aLeft.mType == this, "Unexpected SMIL type");
|
||||||
|
|
||||||
|
const MotionSegmentArray& leftArr = ExtractMotionSegmentArray(aLeft);
|
||||||
|
const MotionSegmentArray& rightArr = ExtractMotionSegmentArray(aRight);
|
||||||
|
|
||||||
|
// If array-lengths don't match, we're trivially non-equal.
|
||||||
|
if (leftArr.Length() != rightArr.Length()) {
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Array-lengths match -- check each array-entry for equality.
|
||||||
|
PRUint32 length = leftArr.Length(); // == rightArr->Length(), if we get here
|
||||||
|
for (PRUint32 i = 0; i < length; ++i) {
|
||||||
|
if (leftArr[i] != rightArr[i]) {
|
||||||
|
return PR_FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return PR_TRUE; // If we get here, we found no differences.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method for Add & CreateMatrix
|
||||||
|
inline static void
|
||||||
|
GetAngleAndPointAtDistance(gfxFlattenedPath* aPath, float aDistance,
|
||||||
|
RotateType aRotateType,
|
||||||
|
gfxFloat& aRotateAngle, // in & out-param.
|
||||||
|
gfxPoint& aPoint) // out-param.
|
||||||
|
{
|
||||||
|
gfxFloat tangentAngle;
|
||||||
|
// NOTE: "0.0" below is distance-off-the-path. (see FindPoint documentation)
|
||||||
|
aPoint = aPath->FindPoint(gfxPoint(aDistance, 0.0), &tangentAngle);
|
||||||
|
|
||||||
|
// Update aRotateAngle if it's auto/auto-reverse
|
||||||
|
switch (aRotateType) {
|
||||||
|
case eRotateType_Explicit:
|
||||||
|
// Leave aRotateAngle as-is.
|
||||||
|
break;
|
||||||
|
case eRotateType_Auto:
|
||||||
|
aRotateAngle = tangentAngle;
|
||||||
|
break;
|
||||||
|
case eRotateType_AutoReverse:
|
||||||
|
aRotateAngle = M_PI + tangentAngle;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
SVGMotionSMILType::Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
|
||||||
|
PRUint32 aCount) const
|
||||||
|
{
|
||||||
|
NS_ABORT_IF_FALSE(aDest.mType == aValueToAdd.mType,
|
||||||
|
"Incompatible SMIL types");
|
||||||
|
NS_ABORT_IF_FALSE(aDest.mType == this, "Unexpected SMIL type");
|
||||||
|
|
||||||
|
MotionSegmentArray& dstArr = ExtractMotionSegmentArray(aDest);
|
||||||
|
const MotionSegmentArray& srcArr = ExtractMotionSegmentArray(aValueToAdd);
|
||||||
|
|
||||||
|
// We're doing a simple add here (as opposed to a sandwich add below). We
|
||||||
|
// only do this when we're accumulating a repeat result.
|
||||||
|
// NOTE: In other nsISMILTypes, we use this method with a barely-initialized
|
||||||
|
// |aDest| value to assist with "by" animation. (In this case,
|
||||||
|
// "barely-initialized" would mean dstArr.Length() would be empty.) However,
|
||||||
|
// we don't do this for <animateMotion>, because we instead use our "by"
|
||||||
|
// value to construct an equivalent "path" attribute, and we use *that* for
|
||||||
|
// our actual animation.
|
||||||
|
NS_ABORT_IF_FALSE(srcArr.Length() == 1, "Invalid source segment arr to add");
|
||||||
|
NS_ABORT_IF_FALSE(dstArr.Length() == 1, "Invalid dest segment arr to add to");
|
||||||
|
const MotionSegment& srcSeg = srcArr[0];
|
||||||
|
const MotionSegment& dstSeg = dstArr[0];
|
||||||
|
NS_ABORT_IF_FALSE(srcSeg.mSegmentType == eSegmentType_PathPoint,
|
||||||
|
"expecting to be adding points from a motion path");
|
||||||
|
NS_ABORT_IF_FALSE(dstSeg.mSegmentType == eSegmentType_PathPoint,
|
||||||
|
"expecting to be adding points from a motion path");
|
||||||
|
|
||||||
|
const PathPointParams& srcParams = srcSeg.mU.mPathPointParams;
|
||||||
|
const PathPointParams& dstParams = dstSeg.mU.mPathPointParams;
|
||||||
|
|
||||||
|
NS_ABORT_IF_FALSE(srcSeg.mRotateType == dstSeg.mRotateType &&
|
||||||
|
srcSeg.mRotateAngle == dstSeg.mRotateAngle,
|
||||||
|
"unexpected angle mismatch");
|
||||||
|
NS_ABORT_IF_FALSE(srcParams.mPath == dstParams.mPath,
|
||||||
|
"unexpected path mismatch");
|
||||||
|
gfxFlattenedPath* path = srcParams.mPath;
|
||||||
|
|
||||||
|
// Use destination to get our rotate angle.
|
||||||
|
gfxFloat rotateAngle = dstSeg.mRotateAngle;
|
||||||
|
gfxPoint dstPt;
|
||||||
|
GetAngleAndPointAtDistance(path, dstParams.mDistToPoint, dstSeg.mRotateType,
|
||||||
|
rotateAngle, dstPt);
|
||||||
|
|
||||||
|
// NOTE: "0.0" below is distance-off-the-path. (see FindPoint documentation)
|
||||||
|
gfxPoint srcPt = path->FindPoint(gfxPoint(srcParams.mDistToPoint, 0.0));
|
||||||
|
|
||||||
|
float newX = dstPt.x + srcPt.x * aCount;
|
||||||
|
float newY = dstPt.y + srcPt.y * aCount;
|
||||||
|
|
||||||
|
// Replace destination's current value -- a point-on-a-path -- with the
|
||||||
|
// translation that results from our addition.
|
||||||
|
dstArr.Clear();
|
||||||
|
dstArr.AppendElement(MotionSegment(newX, newY, rotateAngle));
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
SVGMotionSMILType::SandwichAdd(nsSMILValue& aDest,
|
||||||
|
const nsSMILValue& aValueToAdd) const
|
||||||
|
{
|
||||||
|
NS_ABORT_IF_FALSE(aDest.mType == aValueToAdd.mType,
|
||||||
|
"Incompatible SMIL types");
|
||||||
|
NS_ABORT_IF_FALSE(aDest.mType == this, "Unexpected SMIL type");
|
||||||
|
MotionSegmentArray& dstArr = ExtractMotionSegmentArray(aDest);
|
||||||
|
const MotionSegmentArray& srcArr = ExtractMotionSegmentArray(aValueToAdd);
|
||||||
|
|
||||||
|
// We're only expecting to be adding 1 segment on to the list
|
||||||
|
NS_ABORT_IF_FALSE(srcArr.Length() == 1,
|
||||||
|
"Trying to do sandwich add of more than one value");
|
||||||
|
|
||||||
|
if (!dstArr.AppendElement(srcArr[0])) {
|
||||||
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
SVGMotionSMILType::ComputeDistance(const nsSMILValue& aFrom,
|
||||||
|
const nsSMILValue& aTo,
|
||||||
|
double& aDistance) const
|
||||||
|
{
|
||||||
|
NS_ABORT_IF_FALSE(aFrom.mType == aTo.mType, "Incompatible SMIL types");
|
||||||
|
NS_ABORT_IF_FALSE(aFrom.mType == this, "Unexpected SMIL type");
|
||||||
|
const MotionSegmentArray& fromArr = ExtractMotionSegmentArray(aFrom);
|
||||||
|
const MotionSegmentArray& toArr = ExtractMotionSegmentArray(aTo);
|
||||||
|
|
||||||
|
// ComputeDistance is only used for calculating distances between single
|
||||||
|
// values in a values array. So we should only have one entry in each array.
|
||||||
|
NS_ABORT_IF_FALSE(fromArr.Length() == 1,
|
||||||
|
"Wrong number of elements in from value");
|
||||||
|
NS_ABORT_IF_FALSE(toArr.Length() == 1,
|
||||||
|
"Wrong number of elements in to value");
|
||||||
|
|
||||||
|
const MotionSegment& from = fromArr[0];
|
||||||
|
const MotionSegment& to = toArr[0];
|
||||||
|
|
||||||
|
NS_ABORT_IF_FALSE(from.mSegmentType == to.mSegmentType,
|
||||||
|
"Mismatched MotionSegment types");
|
||||||
|
if (from.mSegmentType == eSegmentType_PathPoint) {
|
||||||
|
const PathPointParams& fromParams = from.mU.mPathPointParams;
|
||||||
|
const PathPointParams& toParams = to.mU.mPathPointParams;
|
||||||
|
NS_ABORT_IF_FALSE(fromParams.mPath == toParams.mPath,
|
||||||
|
"Interpolation endpoints should be from same path");
|
||||||
|
NS_ABORT_IF_FALSE(fromParams.mDistToPoint <= toParams.mDistToPoint,
|
||||||
|
"To value shouldn't be before from value on path");
|
||||||
|
aDistance = fabs(toParams.mDistToPoint - fromParams.mDistToPoint);
|
||||||
|
} else {
|
||||||
|
const TranslationParams& fromParams = from.mU.mTranslationParams;
|
||||||
|
const TranslationParams& toParams = to.mU.mTranslationParams;
|
||||||
|
float dX = toParams.mX - fromParams.mX;
|
||||||
|
float dY = toParams.mY - fromParams.mY;
|
||||||
|
aDistance = NS_hypot(dX, dY);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method for Interpolate()
|
||||||
|
static inline float
|
||||||
|
InterpolateFloat(const float& aStartFlt, const float& aEndFlt,
|
||||||
|
const double& aUnitDistance)
|
||||||
|
{
|
||||||
|
return aStartFlt + aUnitDistance * (aEndFlt - aStartFlt);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
SVGMotionSMILType::Interpolate(const nsSMILValue& aStartVal,
|
||||||
|
const nsSMILValue& aEndVal,
|
||||||
|
double aUnitDistance,
|
||||||
|
nsSMILValue& aResult) const
|
||||||
|
{
|
||||||
|
NS_ABORT_IF_FALSE(aStartVal.mType == aEndVal.mType,
|
||||||
|
"Trying to interpolate different types");
|
||||||
|
NS_ABORT_IF_FALSE(aStartVal.mType == this,
|
||||||
|
"Unexpected types for interpolation");
|
||||||
|
NS_ABORT_IF_FALSE(aResult.mType == this, "Unexpected result type");
|
||||||
|
NS_ABORT_IF_FALSE(aUnitDistance >= 0.0 && aUnitDistance <= 1.0,
|
||||||
|
"unit distance value out of bounds");
|
||||||
|
|
||||||
|
const MotionSegmentArray& startArr = ExtractMotionSegmentArray(aStartVal);
|
||||||
|
const MotionSegmentArray& endArr = ExtractMotionSegmentArray(aEndVal);
|
||||||
|
MotionSegmentArray& resultArr = ExtractMotionSegmentArray(aResult);
|
||||||
|
|
||||||
|
NS_ABORT_IF_FALSE(startArr.Length() <= 1,
|
||||||
|
"Invalid start-point for animateMotion interpolation");
|
||||||
|
NS_ABORT_IF_FALSE(endArr.Length() == 1,
|
||||||
|
"Invalid end-point for animateMotion interpolation");
|
||||||
|
NS_ABORT_IF_FALSE(resultArr.IsEmpty(),
|
||||||
|
"Expecting result to be just-initialized w/ empty array");
|
||||||
|
|
||||||
|
const MotionSegment& endSeg = endArr[0];
|
||||||
|
NS_ABORT_IF_FALSE(endSeg.mSegmentType == eSegmentType_PathPoint,
|
||||||
|
"Expecting to be interpolating along a path");
|
||||||
|
|
||||||
|
const PathPointParams& endParams = endSeg.mU.mPathPointParams;
|
||||||
|
// NOTE: path & angle should match between start & end (since presumably
|
||||||
|
// start & end came from the same <animateMotion> element), unless start is
|
||||||
|
// empty. (as it would be for pure 'to' animation)
|
||||||
|
gfxFlattenedPath* path = endParams.mPath;
|
||||||
|
RotateType rotateType = endSeg.mRotateType;
|
||||||
|
float rotateAngle = endSeg.mRotateAngle;
|
||||||
|
|
||||||
|
float startDist;
|
||||||
|
if (startArr.IsEmpty()) {
|
||||||
|
startDist = 0.0f;
|
||||||
|
} else {
|
||||||
|
const MotionSegment& startSeg = startArr[0];
|
||||||
|
NS_ABORT_IF_FALSE(startSeg.mSegmentType == eSegmentType_PathPoint,
|
||||||
|
"Expecting to be interpolating along a path");
|
||||||
|
const PathPointParams& startParams = startSeg.mU.mPathPointParams;
|
||||||
|
NS_ABORT_IF_FALSE(startSeg.mRotateType == endSeg.mRotateType &&
|
||||||
|
startSeg.mRotateAngle == endSeg.mRotateAngle,
|
||||||
|
"unexpected angle mismatch");
|
||||||
|
NS_ABORT_IF_FALSE(startParams.mPath == endParams.mPath,
|
||||||
|
"unexpected path mismatch");
|
||||||
|
startDist = startParams.mDistToPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the interpolated distance along our path.
|
||||||
|
float resultDist = InterpolateFloat(startDist, endParams.mDistToPoint,
|
||||||
|
aUnitDistance);
|
||||||
|
|
||||||
|
// Construct the intermediate result segment, and put it in our outparam.
|
||||||
|
// AppendElement has guaranteed success here, since Init() allocates 1 slot.
|
||||||
|
resultArr.AppendElement(MotionSegment(path, resultDist,
|
||||||
|
rotateType, rotateAngle));
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ gfxMatrix
|
||||||
|
SVGMotionSMILType::CreateMatrix(const nsSMILValue& aSMILVal)
|
||||||
|
{
|
||||||
|
const MotionSegmentArray& arr = ExtractMotionSegmentArray(aSMILVal);
|
||||||
|
|
||||||
|
gfxMatrix matrix;
|
||||||
|
PRUint32 length = arr.Length();
|
||||||
|
for (PRUint32 i = 0; i < length; i++) {
|
||||||
|
gfxPoint point; // initialized below
|
||||||
|
gfxFloat rotateAngle = arr[i].mRotateAngle; // might get updated below
|
||||||
|
if (arr[i].mSegmentType == eSegmentType_Translation) {
|
||||||
|
point.x = arr[i].mU.mTranslationParams.mX;
|
||||||
|
point.y = arr[i].mU.mTranslationParams.mY;
|
||||||
|
NS_ABORT_IF_FALSE(arr[i].mRotateType == eRotateType_Explicit,
|
||||||
|
"'auto'/'auto-reverse' should have been converted to "
|
||||||
|
"explicit angles when we generated this translation");
|
||||||
|
} else {
|
||||||
|
GetAngleAndPointAtDistance(arr[i].mU.mPathPointParams.mPath,
|
||||||
|
arr[i].mU.mPathPointParams.mDistToPoint,
|
||||||
|
arr[i].mRotateType,
|
||||||
|
rotateAngle, point);
|
||||||
|
}
|
||||||
|
matrix.Translate(point);
|
||||||
|
matrix.Rotate(rotateAngle);
|
||||||
|
}
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* static */ nsSMILValue
|
||||||
|
SVGMotionSMILType::ConstructSMILValue(gfxFlattenedPath* aPath,
|
||||||
|
float aDist,
|
||||||
|
RotateType aRotateType,
|
||||||
|
float aRotateAngle)
|
||||||
|
{
|
||||||
|
nsSMILValue smilVal(&SVGMotionSMILType::sSingleton);
|
||||||
|
MotionSegmentArray& arr = ExtractMotionSegmentArray(smilVal);
|
||||||
|
|
||||||
|
// AppendElement has guaranteed success here, since Init() allocates 1 slot.
|
||||||
|
arr.AppendElement(MotionSegment(aPath, aDist, aRotateType, aRotateAngle));
|
||||||
|
return smilVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace mozilla
|
114
content/svg/content/src/SVGMotionSMILType.h
Normal file
114
content/svg/content/src/SVGMotionSMILType.h
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/* -*- 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) 2010
|
||||||
|
* the Initial Developer. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
* Daniel Holbert <dholbert@mozilla.com>
|
||||||
|
*
|
||||||
|
* 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 ***** */
|
||||||
|
|
||||||
|
/* implementation of nsISMILType for use by <animateMotion> element */
|
||||||
|
|
||||||
|
#ifndef MOZILLA_SVGMOTIONSMILTYPE_H_
|
||||||
|
#define MOZILLA_SVGMOTIONSMILTYPE_H_
|
||||||
|
|
||||||
|
#include "nsISMILType.h"
|
||||||
|
#include "gfxMatrix.h"
|
||||||
|
#include "nsTArray.h"
|
||||||
|
class nsSVGPathElement;
|
||||||
|
class nsSMILValue;
|
||||||
|
class gfxFlattenedPath;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MotionRotateType: Enum to indicate the type of our "rotate" attribute.
|
||||||
|
*/
|
||||||
|
enum RotateType {
|
||||||
|
eRotateType_Explicit, // for e.g. rotate="45"/"45deg"/"0.785rad"
|
||||||
|
eRotateType_Auto, // for rotate="auto"
|
||||||
|
eRotateType_AutoReverse // for rotate="auto-reverse"
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SVGMotionSMILType: Implements the nsISMILType interface for SMIL animations
|
||||||
|
* from <animateMotion>.
|
||||||
|
*
|
||||||
|
* NOTE: Even though there's technically no "motion" attribute, we behave in
|
||||||
|
* many ways as if there were, for simplicity.
|
||||||
|
*/
|
||||||
|
class SVGMotionSMILType : public nsISMILType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Singleton for nsSMILValue objects to hold onto.
|
||||||
|
static SVGMotionSMILType sSingleton;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// nsISMILType Methods
|
||||||
|
// -------------------
|
||||||
|
virtual void Init(nsSMILValue& aValue) const;
|
||||||
|
virtual void Destroy(nsSMILValue& aValue) const;
|
||||||
|
virtual nsresult Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const;
|
||||||
|
virtual PRBool IsEqual(const nsSMILValue& aLeft,
|
||||||
|
const nsSMILValue& aRight) const;
|
||||||
|
virtual nsresult Add(nsSMILValue& aDest,
|
||||||
|
const nsSMILValue& aValueToAdd,
|
||||||
|
PRUint32 aCount) const;
|
||||||
|
virtual nsresult SandwichAdd(nsSMILValue& aDest,
|
||||||
|
const nsSMILValue& aValueToAdd) 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;
|
||||||
|
public:
|
||||||
|
// Used to generate a transform matrix from an <animateMotion> nsSMILValue.
|
||||||
|
static gfxMatrix CreateMatrix(const nsSMILValue& aSMILVal);
|
||||||
|
|
||||||
|
// Used to generate a nsSMILValue for the point at the given distance along
|
||||||
|
// the given path.
|
||||||
|
static nsSMILValue ConstructSMILValue(gfxFlattenedPath* aPath,
|
||||||
|
float aDist,
|
||||||
|
RotateType aRotateType,
|
||||||
|
float aRotateAngle);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Private constructor & destructor: prevent instances beyond my singleton,
|
||||||
|
// and prevent others from deleting my singleton.
|
||||||
|
SVGMotionSMILType() {}
|
||||||
|
~SVGMotionSMILType() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // MOZILLA_SVGMOTIONSMILTYPE_H_
|
@ -41,7 +41,7 @@
|
|||||||
#include "nsSVGAnimationElement.h"
|
#include "nsSVGAnimationElement.h"
|
||||||
#include "nsIDOMSVGAnimateMotionElement.h"
|
#include "nsIDOMSVGAnimateMotionElement.h"
|
||||||
#include "nsSVGEnum.h"
|
#include "nsSVGEnum.h"
|
||||||
#include "nsSMILAnimationFunction.h"
|
#include "SVGMotionSMILAnimationFunction.h"
|
||||||
|
|
||||||
#include "nsCOMArray.h"
|
#include "nsCOMArray.h"
|
||||||
#include "nsIDOMSVGPathSeg.h"
|
#include "nsIDOMSVGPathSeg.h"
|
||||||
@ -59,7 +59,7 @@ protected:
|
|||||||
nsINodeInfo *aNodeInfo);
|
nsINodeInfo *aNodeInfo);
|
||||||
nsSVGAnimateMotionElement(nsINodeInfo* aNodeInfo);
|
nsSVGAnimateMotionElement(nsINodeInfo* aNodeInfo);
|
||||||
|
|
||||||
nsSMILAnimationFunction mAnimationFunction;
|
mozilla::SVGMotionSMILAnimationFunction mAnimationFunction;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// interfaces:
|
// interfaces:
|
||||||
@ -76,6 +76,9 @@ public:
|
|||||||
|
|
||||||
// nsISMILAnimationElement
|
// nsISMILAnimationElement
|
||||||
virtual nsSMILAnimationFunction& AnimationFunction();
|
virtual nsSMILAnimationFunction& AnimationFunction();
|
||||||
|
virtual nsIAtom* GetTargetAttributeName() const;
|
||||||
|
virtual nsSMILTargetAttrType GetTargetAttributeType() const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
NS_IMPL_NS_NEW_SVG_ELEMENT(AnimateMotion)
|
NS_IMPL_NS_NEW_SVG_ELEMENT(AnimateMotion)
|
||||||
@ -117,3 +120,21 @@ nsSVGAnimateMotionElement::AnimationFunction()
|
|||||||
{
|
{
|
||||||
return mAnimationFunction;
|
return mAnimationFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsIAtom*
|
||||||
|
nsSVGAnimateMotionElement::GetTargetAttributeName() const
|
||||||
|
{
|
||||||
|
// <animateMotion> doesn't take an attributeName, since it doesn't target an
|
||||||
|
// 'attribute' per se. We'll use a unique dummy attribute-name so that our
|
||||||
|
// nsSMILTargetIdentifier logic (which requires a attribute name) still works.
|
||||||
|
return nsGkAtoms::mozAnimateMotionDummyAttr;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsSMILTargetAttrType
|
||||||
|
nsSVGAnimateMotionElement::GetTargetAttributeType() const
|
||||||
|
{
|
||||||
|
// <animateMotion> doesn't take an attributeType, since it doesn't target an
|
||||||
|
// 'attribute' per se. We'll just return 'XML' for simplicity. (This just
|
||||||
|
// needs to match what we expect in nsSVGElement::GetAnimAttr.)
|
||||||
|
return eSMILTargetAttrType_XML;
|
||||||
|
}
|
||||||
|
@ -94,6 +94,7 @@
|
|||||||
#include "nsSMILMappedAttribute.h"
|
#include "nsSMILMappedAttribute.h"
|
||||||
#include "nsSVGTransformSMILAttr.h"
|
#include "nsSVGTransformSMILAttr.h"
|
||||||
#include "nsSVGAnimatedTransformList.h"
|
#include "nsSVGAnimatedTransformList.h"
|
||||||
|
#include "SVGMotionSMILAttr.h"
|
||||||
#include "nsIDOMSVGTransformable.h"
|
#include "nsIDOMSVGTransformable.h"
|
||||||
#endif // MOZ_SMIL
|
#endif // MOZ_SMIL
|
||||||
|
|
||||||
@ -1954,6 +1955,11 @@ nsSVGElement::GetAnimatedAttr(nsIAtom* aName)
|
|||||||
return new nsSVGTransformSMILAttr(list, this);
|
return new nsSVGTransformSMILAttr(list, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Motion (fake 'attribute' for animateMotion)
|
||||||
|
if (aName == nsGkAtoms::mozAnimateMotionDummyAttr) {
|
||||||
|
return new mozilla::SVGMotionSMILAttr(this);
|
||||||
|
}
|
||||||
|
|
||||||
// Lengths:
|
// Lengths:
|
||||||
LengthAttributesInfo info = GetLengthInfo();
|
LengthAttributesInfo info = GetLengthInfo();
|
||||||
for (PRUint32 i = 0; i < info.mLengthCount; i++) {
|
for (PRUint32 i = 0; i < info.mLengthCount; i++) {
|
||||||
|
@ -145,6 +145,11 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual gfxMatrix PrependLocalTransformTo(const gfxMatrix &aMatrix);
|
virtual gfxMatrix PrependLocalTransformTo(const gfxMatrix &aMatrix);
|
||||||
|
|
||||||
|
// Setter for to set the current <animateMotion> transformation
|
||||||
|
// Only visible for nsSVGGraphicElement, so it's a no-op here, and that
|
||||||
|
// subclass has the useful implementation.
|
||||||
|
virtual void SetAnimateMotionTransform(const gfxMatrix* aMatrix) {/*no-op*/}
|
||||||
|
|
||||||
virtual void DidChangeLength(PRUint8 aAttrEnum, PRBool aDoSetAttr);
|
virtual void DidChangeLength(PRUint8 aAttrEnum, PRBool aDoSetAttr);
|
||||||
virtual void DidChangeNumber(PRUint8 aAttrEnum, PRBool aDoSetAttr);
|
virtual void DidChangeNumber(PRUint8 aAttrEnum, PRBool aDoSetAttr);
|
||||||
virtual void DidChangeInteger(PRUint8 aAttrEnum, PRBool aDoSetAttr);
|
virtual void DidChangeInteger(PRUint8 aAttrEnum, PRBool aDoSetAttr);
|
||||||
|
@ -185,21 +185,37 @@ nsSVGGraphicElement::IsEventName(nsIAtom* aName)
|
|||||||
gfxMatrix
|
gfxMatrix
|
||||||
nsSVGGraphicElement::PrependLocalTransformTo(const gfxMatrix &aMatrix)
|
nsSVGGraphicElement::PrependLocalTransformTo(const gfxMatrix &aMatrix)
|
||||||
{
|
{
|
||||||
if (!mTransforms)
|
gfxMatrix result(aMatrix);
|
||||||
return aMatrix;
|
|
||||||
|
|
||||||
nsresult rv;
|
// animateMotion's resulting transform is supposed to apply *on top of*
|
||||||
nsCOMPtr<nsIDOMSVGTransformList> transforms;
|
// any transformations from the |transform| attribute. So since we're
|
||||||
rv = mTransforms->GetAnimVal(getter_AddRefs(transforms));
|
// PRE-multiplying, we need to apply the animateMotion transform *first*.
|
||||||
NS_ENSURE_SUCCESS(rv, aMatrix);
|
if (mAnimateMotionTransform) {
|
||||||
PRUint32 count;
|
result.PreMultiply(*mAnimateMotionTransform);
|
||||||
transforms->GetNumberOfItems(&count);
|
}
|
||||||
if (count == 0)
|
|
||||||
return aMatrix;
|
|
||||||
|
|
||||||
nsCOMPtr<nsIDOMSVGMatrix> matrix =
|
if (mTransforms) {
|
||||||
nsSVGTransformList::GetConsolidationMatrix(transforms);
|
nsresult rv;
|
||||||
return gfxMatrix(aMatrix).PreMultiply(nsSVGUtils::ConvertSVGMatrixToThebes(matrix));
|
nsCOMPtr<nsIDOMSVGTransformList> transforms;
|
||||||
|
rv = mTransforms->GetAnimVal(getter_AddRefs(transforms));
|
||||||
|
NS_ENSURE_SUCCESS(rv, aMatrix);
|
||||||
|
PRUint32 count;
|
||||||
|
transforms->GetNumberOfItems(&count);
|
||||||
|
if (count > 0) {
|
||||||
|
nsCOMPtr<nsIDOMSVGMatrix> matrix =
|
||||||
|
nsSVGTransformList::GetConsolidationMatrix(transforms);
|
||||||
|
result.PreMultiply(nsSVGUtils::ConvertSVGMatrixToThebes(matrix));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
nsSVGGraphicElement::SetAnimateMotionTransform(const gfxMatrix* aMatrix)
|
||||||
|
{
|
||||||
|
mAnimateMotionTransform = aMatrix ? new gfxMatrix(*aMatrix) : nsnull;
|
||||||
|
DidAnimateTransform();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
@ -63,6 +63,7 @@ public:
|
|||||||
NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const;
|
NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const;
|
||||||
|
|
||||||
virtual gfxMatrix PrependLocalTransformTo(const gfxMatrix &aMatrix);
|
virtual gfxMatrix PrependLocalTransformTo(const gfxMatrix &aMatrix);
|
||||||
|
virtual void SetAnimateMotionTransform(const gfxMatrix* aMatrix);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// nsSVGElement overrides
|
// nsSVGElement overrides
|
||||||
@ -73,6 +74,9 @@ protected:
|
|||||||
|
|
||||||
nsCOMPtr<nsIDOMSVGAnimatedTransformList> mTransforms;
|
nsCOMPtr<nsIDOMSVGAnimatedTransformList> mTransforms;
|
||||||
|
|
||||||
|
// XXX maybe move this to property table, to save space on un-animated elems?
|
||||||
|
nsAutoPtr<gfxMatrix> mAnimateMotionTransform;
|
||||||
|
|
||||||
// helper
|
// helper
|
||||||
nsresult CreateTransformList();
|
nsresult CreateTransformList();
|
||||||
};
|
};
|
||||||
|
@ -118,6 +118,13 @@ class nsSVGDisplayContainerFrame;
|
|||||||
#define SVG_WSP_DELIM "\x20\x9\xD\xA"
|
#define SVG_WSP_DELIM "\x20\x9\xD\xA"
|
||||||
#define SVG_COMMA_WSP_DELIM "," SVG_WSP_DELIM
|
#define SVG_COMMA_WSP_DELIM "," SVG_WSP_DELIM
|
||||||
|
|
||||||
|
inline PRBool
|
||||||
|
IsSVGWhitespace(char aChar)
|
||||||
|
{
|
||||||
|
return aChar == '\x20' || aChar == '\x9' ||
|
||||||
|
aChar == '\xD' || aChar == '\xA';
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Checks the svg enable preference and if a renderer could
|
* Checks the svg enable preference and if a renderer could
|
||||||
* successfully be created. Declared as a function instead of a
|
* successfully be created. Declared as a function instead of a
|
||||||
|
Loading…
Reference in New Issue
Block a user