FileDocCategorySizeDatePackage
AnimateMotion.javaAPI DocphoneME MR2 API (J2ME)15331Wed May 02 18:00:34 BST 2007com.sun.perseus.model

AnimateMotion

public class AnimateMotion extends AbstractAnimate
AnimateMotion represents an SVG Tiny <animateMotion> element.
version
$Id: AnimateMotion.java,v 1.5 2006/06/29 10:47:29 ln156897 Exp $

Fields Summary
static final int
ROTATE_ANGLE
Rotate type when an angle is specified in the rotate attribute.
static final int
ROTATE_AUTO
Rotate type when the rotate attribute is set to auto.
static final int
ROTATE_AUTO_REVERSE
Rotate type when the rotate attribute is set to auto-reverse
String
path
The path attribute value.
float[]
keyPoints
The keyPoints attribute value
float
rotate
The rotate angle. Used if rotateType is ROTATE_ANGLE
float
cosRotate
The rotation's cos value
float
sinRotate
The rotation angle's sin value.
int
rotateType
The rotate type. One of ROTATE_ANGLE (an angle was specified) or ROTATE_AUTO, ROTATE_AUTO_REVERSE
RefValues
pathRefValues
Used, temporarily, to hold the refValues for the path attribute.
RefValues
mpathRefValues
Used, temporarily, to hold the refValues for mpath child.
Constructors Summary
public AnimateMotion(DocumentNode ownerDocument)
Builds a new AnimateMotion element that belongs to the given document. This AnimateMotion will belong to the DocumentNode's time container.

param
ownerDocument the document this node belongs to.
throws
IllegalArgumentException if the input ownerDocument is null


                                              
        
        super(ownerDocument, SVGConstants.SVG_ANIMATE_MOTION_TAG);

        // Default calcMode for animateMotion is paced.
        calcMode = CALC_MODE_PACED;

        // AnimateMotion operates on a fixed trait name
        traitName = SVGConstants.SVG_MOTION_PSEUDO_ATTRIBUTE;
    
Methods Summary
protected voidcomputeRefTimes()
Computes refTimes from the calcMode and keyTimes attributes. Validates that the keyTimes attribute is compatible with the animate set up. This may be overridden by subclasses (e.g., animateMotion), when there are special rules for checking keyTimes compatiblity.

        // if there is no keyPoints defined or if the calcMode is
        // paced, we use the default behavior.
        if (keyPoints == null || actualCalcMode == CALC_MODE_PACED) {
            super.computeRefTimes();
            return;
        }

        // Check keyTimes is compatible with the animation specification.
        // 
        // a) keyTimes should be specified (i.e., not null)
        //
        // b) In all cases, the first keyTime must be zero.
        // 
        // c) For non-discrete animations, the last keyTime must be one.
        //
        // d) There should be as many keyTimes as there are keyPoints
        //
        if (/* a) */ keyTimes == null
            ||
            /* b) */ keyTimes.length < 1 || keyTimes[0] != 0
            ||
            /* c) */ (actualCalcMode != CALC_MODE_DISCRETE 
                      && 
                      keyTimes[keyTimes.length - 1] != 1)
            ||
            /* d) */ keyTimes.length != keyPoints.length) {
            throw animationError(
                    idRef,
                    traitNamespace,
                    traitName,
                    targetElement.getNamespaceURI(),
                    targetElement.getLocalName(),
                    getId(),
                    getNamespaceURI(),
                    getLocalName(),
                    Messages.formatMessage(
                        Messages.ERROR_INVALID_ANIMATION_KEY_TIMES, 
                        new Object[] {
                            getTrait(SVGConstants.SVG_KEY_TIMES_ATTRIBUTE)
                        }));
        }
        
        // If the calcMode is _not_ discrete, we trim the last '1' 
        // value.
        if (actualCalcMode != CALC_MODE_DISCRETE) {
            refTimes = new float[keyTimes.length - 1];
            System.arraycopy(keyTimes, 0, refTimes, 0, refTimes.length);
        } else {
            refTimes = keyTimes;
        }
    
public java.lang.StringgetTraitImpl(java.lang.String name)

        if (SVGConstants.SVG_PATH_ATTRIBUTE == name) {
            return path;
        } else if (SVGConstants.SVG_KEY_POINTS_ATTRIBUTE == name) {
            return toStringTrait(keyPoints);
        } else if (SVGConstants.SVG_ROTATE_ATTRIBUTE == name) {
            switch (rotateType) {
            case ROTATE_ANGLE:
                return Float.toString(rotate);
            case ROTATE_AUTO:
                return SVGConstants.SVG_AUTO_VALUE;
            case ROTATE_AUTO_REVERSE:
            default:
                return SVGConstants.SVG_AUTO_REVERSE_VALUE;
            }
        } else {
            return super.getTraitImpl(name);
        }
    
protected voidmapToSegmentProgress(int si, float sp, float[] sisp)
The following call lets the animate implementation map the time segment indices and the time segment penetration into refValues indices and penetration, in case these are different. Typically, these are the same, but they may be different, for example in the case of animateMotion with keyPoints.

param
si the time segment index.
param
sp the segment penetration.
param
sisp an array where the mapped si and sp value should be stored. si is at index 0 and sp at index 1.

        // animateMotion also maps to segments directly unless there
        // is a keyPoints attribute specified, in which case it 
        // overrides the default behavior.
        if (keyPoints == null || actualCalcMode == CALC_MODE_PACED) {
            super.mapToSegmentProgress(si, sp, sisp);
            return;
        }

        // We are dealing with a keyPoints animateMotion.
        // We only do the computation on the first component, because
        // the input and output indices for animateMotion with keyTimes
        // should be the same on all components (by definition).
        float startDist = keyPoints[si];
        float endDist = keyPoints[si + 1];

        float dist = sp * endDist + (1 - sp) * startDist;

        // Now that we know how far along we should be on the path, 
        // find the corresponding segment.
        ((MotionRefValues) refValues).getSegmentAtDist(sisp, dist);
    
public ElementNodenewInstance(DocumentNode doc)
Used by DocumentNode to create a new instance from a prototype TimedElementNode.

param
doc the DocumentNode for which a new node is should be created.
return
a new TimedElementNode for the requested document.

        return new AnimateMotion(doc);
    
final voidselectRefValuesExtra()
Computes the 'right' source for reference values, depending on the precedence rules for the different values sources.

throws
DOMException if there is no way to compute a set of reference values, for example if none of the values sources is specified.

        if (mpathRefValues != null) {
            refValues = mpathRefValues;
        } else if (pathRefValues != null) {
            refValues = pathRefValues;
        }
    
public voidsetTraitImpl(java.lang.String name, java.lang.String value)

param
name the trait's name.
param
value the trait's value.
throws
DOMException with error code NOT_SUPPORTED_ERR if the requested trait is not supported on this element or null.
throws
DOMException with error code TYPE_MISMATCH_ERR if the requested trait's value cannot be specified as a String
throws
DOMException with error code INVALID_ACCESS_ERR if the input value is an invalid value for the given trait or null.
throws
DOMException with error code NO_MODIFICATION_ALLOWED_ERR: if attempt is made to change readonly trait.

        if (SVGConstants.SVG_PATH_ATTRIBUTE == name) {
            checkWriteLoading(name);
            // path values are validated in the validate() method,
            // just like to/from/by and values are
            path = value;
        } else if (SVGConstants.SVG_KEY_POINTS_ATTRIBUTE == name) {
            checkWriteLoading(name);
            keyPoints = parseFloatArrayTrait(name, value, ';");
        } else if (SVGConstants.SVG_ROTATE_ATTRIBUTE == name) {
            checkWriteLoading(name);
            
            if (SVGConstants.SVG_AUTO_VALUE.equals(value)) {
                rotate = 0;
                rotateType = ROTATE_AUTO;
            } else if (SVGConstants.SVG_AUTO_REVERSE_VALUE.equals(value)) {
                rotate = 0;
                rotateType = ROTATE_AUTO_REVERSE;
            } else {
                // The value is neither 'auto' nor 'auto-reverse'. It 
                // must be an angle value.
                rotate = parseFloatTrait(name, value);
                cosRotate = MathSupport.cos(MathSupport.toRadians(rotate));
                sinRotate = MathSupport.sin(MathSupport.toRadians(rotate));
                rotateType = ROTATE_ANGLE;
            }
        } else {
            super.setTraitImpl(name, value);
        }
    
booleansupportsTrait(java.lang.String traitName)

param
traitName the name of the trait which the element may support.
return
true if this element supports the given trait in one of the trait accessor methods.

        if (SVGConstants.SVG_PATH_ATTRIBUTE == traitName
            ||
            SVGConstants.SVG_KEY_POINTS_ATTRIBUTE == traitName
            ||
            SVGConstants.SVG_ROTATE_ATTRIBUTE == traitName) {
            return true;
        } else {
            return super.supportsTrait(traitName);
        }
    
final voidvalidateValuesExtra()
Validates the path and mpath values sources.

throws
DOMException if there is a validation error, for example if the to value is incompatible with the target trait or if the target trait is not animatable.

        // Validate the path attribute value
        pathRefValues = null;
        if (path != null) {
            pathRefValues = traitAnim.toRefValues(
                    this,
                    new String[] {path},
                    null,
                    SVGConstants.SVG_PATH_ATTRIBUTE);
        }

        // Now, validate the mpath child, if any.
        mpathRefValues = null;
        SVGElement c = (SVGElement) getFirstElementChild();
        SVGElement mpath = null;
        while (c != null) {
            if (SVGConstants.SVG_MPATH_TAG.equals(c.getLocalName())
                &&
                SVGConstants.SVG_NAMESPACE_URI.equals(c.getNamespaceURI())) {
                mpath = c;
                break;
            }
            c = (SVGElement) c.getNextElementSibling();
        }

        if (mpath != null) {
            String pathHref = ((ElementNode) mpath).getTraitNSImpl(
                    SVGConstants.XLINK_NAMESPACE_URI,
                    SVGConstants.SVG_HREF_ATTRIBUTE);
            if (pathHref != null) {
                boolean pathHrefError = false;
                if (pathHref.startsWith("#")) {
                    String pathId = pathHref.substring(1);
                    ElementNode path = 
                            (ElementNode) ownerDocument.getElementById(pathId);
                    if (path != null) {
                        mpathRefValues = traitAnim.toRefValues(
                                this,
                                new String[] {
                                    path.getTraitImpl(
                                        SVGConstants.SVG_D_ATTRIBUTE)
                                },
                                null,
                                SVGConstants.SVG_D_ATTRIBUTE);
                    } else {
                        pathHrefError = true;
                    }
                } else {
                    pathHrefError = true;
                }

                if (pathHrefError) {
                    throw animationError(idRef,
                                         traitNamespace,
                                         traitName,
                                         targetElement.getNamespaceURI(),
                                         targetElement.getLocalName(),
                                         getId(),
                                         getNamespaceURI(),
                                         getLocalName(),
                                         Messages.formatMessage
                                         (Messages.ERROR_INVALID_MPATH_HREF, 
                                          new Object[] {pathHref}));
                }
            } else {
                throw animationError(idRef,
                                     traitNamespace,
                                     traitName,
                                     targetElement.getNamespaceURI(),
                                     targetElement.getLocalName(),
                                     getId(),
                                     getNamespaceURI(),
                                     getLocalName(),
                                     Messages.formatMessage
                                     (Messages.ERROR_MISSING_MPATH_HREF, null));
            }
        }