001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.perseus.model;
028:
029: import org.w3c.dom.DOMException;
030: import org.w3c.dom.events.Event;
031:
032: import com.sun.perseus.util.SVGConstants;
033:
034: /**
035: * The <code>Animation</code> class is the base class for all the
036: * SVG animation elements. Note that this is <em>not</em> the base
037: * class for media elements such as <code><audio></code> or
038: * <code><video></code>.
039: *
040: * The <code>Animation</code> class is the abstraction manipulated
041: * by <code>TraitAnim</code> to compose the chain of currently
042: * active animations in priority order.
043: *
044: * @version $Id: Animation.java,v 1.5 2006/06/29 10:47:29 ln156897 Exp $
045: */
046: public abstract class Animation extends TimedElementNode implements
047: BaseValue, IDRef {
048: /**
049: * Constant used by default to identify the type of animation values.
050: * Derived classes, such as AnimateTransform, may use other values.
051: */
052: public static final int TYPE_GENERIC = 1;
053:
054: /**
055: * Controls whether the animation has an effect on its target or not.
056: * There are situations where the animation may have no effect, for
057: * example when none of the values/to/from/by attributes are specified
058: * on an <animateTranform> or <animate>.
059: */
060: boolean hasNoEffect;
061:
062: /**
063: * The associated TraitAnim
064: */
065: TraitAnim traitAnim;
066:
067: /**
068: * This animation's base value, if it needs a base value.
069: * The base value is needed in some scenarios, for example
070: * in the case of 'to-animations'.
071: */
072: BaseValue baseVal;
073:
074: /**
075: * This animation's target element.
076: */
077: ElementNode targetElement;
078:
079: /**
080: * This animation's target trait name.
081: */
082: String traitName;
083:
084: /**
085: * This animation's target trait namespace.
086: */
087: String traitNamespace;
088:
089: /**
090: * The identifier of the target animation element.
091: */
092: String idRef;
093:
094: /**
095: * The type of animation.
096: */
097: int type = TYPE_GENERIC;
098:
099: /**
100: * Builds a new animation element that belongs to the given
101: * document. This <code>Animation</code> will belong
102: * to the <code>DocumentNode</code>'s time container.
103: *
104: * @param ownerDocument the document this node belongs to.
105: * @param localName the element's local name
106: * @throws IllegalArgumentException if the input ownerDocument is null
107: */
108: public Animation(final DocumentNode ownerDocument,
109: final String localName) {
110: super (ownerDocument, localName);
111:
112: // If the document is _not_ loaded (i.e., we are at parse time),
113: // add this animation to the document's animations vector for
114: // validation at the end of the loading phase.
115: if (!ownerDocument.loaded) {
116: ownerDocument.animations.addElement(this );
117: }
118: }
119:
120: /**
121: * Should be called when the animation is the target of an hyperlink.
122: */
123: public void activate() {
124: timedElementSupport.activate();
125: }
126:
127: /**
128: * Sets this <code>Animation</code> targetElement's idRef
129: *
130: * @param idRef the identifier of the animation's target element.
131: * Should not be null
132: */
133: public void setIdRef(final String idRef) {
134: this .idRef = idRef;
135: ownerDocument.resolveIDRef(this , idRef);
136: }
137:
138: /**
139: * @return the <code>Use</code> element's idRef.
140: */
141: public String getIdRef() {
142: return idRef;
143: }
144:
145: /**
146: * <code>IDRef</code> implementation.
147: *
148: * @param ref the resolved reference (mapped from the
149: * id passed to the setIdRef method).
150: */
151: public void resolveTo(final ElementNode ref) {
152: targetElement = ref;
153: }
154:
155: /**
156: * Computes the animation value for the current animation's
157: * simple time.
158: *
159: * @return the current animation value.
160: */
161: final Object[] compute() {
162: return f(timedElementSupport.lastSampleTime);
163: }
164:
165: /**
166: * This is the animation function, the heart of the animation
167: * engine. There are multiple implementations of that function,
168: * and no good default one, so this method is abstract.
169: *
170: * @param t the animation's simple time.
171: */
172: abstract Object[] f(final long t);
173:
174: /**
175: * Returns the BaseValue as an array of objects.
176: *
177: * @return the base value as an object array. The dimensions of the
178: * returned array depend on the trait.
179: * @see com.sun.perseus.model.BaseValue
180: */
181: public Object[] getBaseValue() {
182: return compute();
183: }
184:
185: /**
186: * Event dispatching override, to capture begin and end events.
187: *
188: * When a begin event occurs, the animation adds itself to the target
189: * element and trait's TraitAnim.
190: *
191: * When an end event occurs, the animation removes itself from the target
192: * element and trait's TraitAnim if the animation is not in the frozen
193: * state.
194: *
195: * @param evt the event that occured
196: */
197: public void dispatchEvent(final ModelEvent evt) {
198: super .dispatchEvent(evt);
199:
200: if (targetElement != null) {
201: if (TimedElementSupport.BEGIN_EVENT_TYPE.equals(evt
202: .getType())
203: || TimedElementSupport.SEEK_BEGIN_EVENT_TYPE
204: .equals(evt.getType())) {
205: // Remove the animation, just in case the animation was
206: // previously frozen.
207: if (traitAnim != null && !hasNoEffect) {
208: traitAnim.removeAnimation(this );
209:
210: // Now, add the animation.
211: traitAnim.addAnimation(this );
212: }
213: } else if (TimedElementSupport.LAST_DUR_END_EVENT_TYPE
214: .equals(evt.getType())) {
215: // Only remove the animation if it is _not_ frozen.
216: if ((timedElementSupport.fillBehavior != TimedElementSupport.FILL_BEHAVIOR_FREEZE)
217: && traitAnim != null && !hasNoEffect) {
218: traitAnim.removeAnimation(this );
219: }
220: } else if (TimedElementSupport.SEEK_END_EVENT_TYPE
221: .equals(evt.getType())
222: && traitAnim != null && !hasNoEffect) {
223: // Remove the animation no matter what
224: traitAnim.removeAnimation(this );
225: }
226: }
227: }
228:
229: /**
230: * Supported NS traits: xlink:href
231: *
232: * @param namespaceURI the trait's namespace.
233: * @param traitName the name of the trait which the element may support.
234: * @return true if this element supports the given trait in one of the
235: * trait accessor methods.
236: */
237: boolean supportsTraitNS(final String namespaceURI,
238: final String traitName) {
239: if (SVGConstants.XLINK_NAMESPACE_URI.equals(namespaceURI)
240: && SVGConstants.SVG_HREF_ATTRIBUTE.equals(traitName)) {
241: return true;
242: } else {
243: return super .supportsTraitNS(namespaceURI, traitName);
244: }
245: }
246:
247: /**
248: * Set handles the xlink href attribute
249: *
250: * @param namespaceURI the requested trait's namespace URI.
251: * @param name the requested trait's local name (i.e., un-prefixed, as
252: * "href")
253: * @return the requested trait's string value.
254: *
255: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
256: * trait is not supported on this element or null.
257: * @throws DOMException with error code TYPE_MISMATCH_ERR if requested
258: * trait's computed value cannot be converted to a String (SVG Tiny only).
259: * @throws SecurityException if the application does not have the necessary
260: * privilege rights to access this (SVG) content.
261: */
262: public String getTraitNSImpl(String namespaceURI, String name)
263: throws DOMException {
264: if (SVGConstants.XLINK_NAMESPACE_URI.equals(namespaceURI)
265: && SVGConstants.SVG_HREF_ATTRIBUTE.equals(name)) {
266: if (idRef == null) {
267: return "";
268: }
269: return "#" + idRef;
270: } else {
271: return super .getTraitNSImpl(namespaceURI, name);
272: }
273: }
274:
275: /**
276: * Set supports the xlink:href trait.
277: *
278: * @param namespaceURI the trait's namespace.
279: * @param name the trait's local name (un-prefixed, e.g., "href");
280: * @param value the new trait value (e.g., "http://www.sun.com/mypng.png")
281: *
282: * @throws DOMException with error code NOT_SUPPORTED_ERROR if the requested
283: * trait is not supported on this element or null.
284: * @throws DOMException with error code TYPE_MISMATCH_ERR if the requested
285: * trait's value cannot be specified as a String
286: * @throws DOMException with error code INVALID_ACCESS_ERR if the input
287: * value is an invalid value for the given trait or null.
288: * @throws DOMException with error code NO_MODIFICATION_ALLOWED_ERR: if
289: * attempt is made to change readonly trait.
290: * @throws SecurityException if the application does not have the necessary
291: * privilege rights to access this (SVG) content.
292: */
293: public void setTraitNSImpl(final String namespaceURI,
294: final String name, final String value) throws DOMException {
295: if (SVGConstants.XLINK_NAMESPACE_URI.equals(namespaceURI)
296: && SVGConstants.SVG_HREF_ATTRIBUTE.equals(name)) {
297: if (value == null || !value.startsWith("#")) {
298: throw illegalTraitValue(name, value);
299: }
300: setIdRef(value.substring(1));
301: } else {
302: super .setTraitNSImpl(namespaceURI, name, value);
303: }
304: }
305:
306: /**
307: * This method can be overridden by specific implementations to validate
308: * that the various values attributes (values, to, from, by or any subset of
309: * these) are valid i.e., compatible with the target element and target
310: * trait.
311: *
312: * There are two situations when this method is called:
313: * - parse time. When the document has been fully loaded, it validates all
314: * animations.
315: * - run time. When a new animation is created, it validates itself when
316: * it is hooked into the tree (i.e., when its parent node is set).
317: */
318: abstract void validate();
319:
320: /**
321: * When an Animation is hooked into the document tree, it needs
322: * to validate (only if the Document is loaded).
323: */
324: final void nodeHookedInDocumentTree() {
325: super .nodeHookedInDocumentTree();
326:
327: if (ownerDocument.loaded) {
328: validate();
329: }
330: }
331:
332: /**
333: * When an Animation is removed from the document tree, it needs
334: * to remove itself from its associated traitAnim.
335: */
336: final void nodeUnhookedFromDocumentTree() {
337: super.nodeUnhookedFromDocumentTree();
338:
339: if (traitAnim != null) {
340: traitAnim.removeAnimation(this);
341: }
342: }
343:
344: }
|