/*

   Licensed to the Apache Software Foundation (ASF) under one or more
   contributor license agreements.  See the NOTICE file distributed with
   this work for additional information regarding copyright ownership.
   The ASF licenses this file to You under the Apache License, Version 2.0
   (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.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

 */
package org.apache.batik.bridge;

import java.awt.Color;
import java.awt.Paint;
import java.lang.ref.WeakReference;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Arrays;
import java.util.Set;

import org.apache.batik.anim.AnimationEngine;
import org.apache.batik.anim.AnimationException;
import org.apache.batik.anim.dom.AnimationTarget;
import org.apache.batik.anim.dom.SVGOMDocument;
import org.apache.batik.anim.dom.SVGOMElement;
import org.apache.batik.anim.dom.SVGStylableElement;
import org.apache.batik.anim.timing.TimedDocumentRoot;
import org.apache.batik.anim.timing.TimedElement;
import org.apache.batik.anim.values.AnimatableAngleValue;
import org.apache.batik.anim.values.AnimatableAngleOrIdentValue;
import org.apache.batik.anim.values.AnimatableBooleanValue;
import org.apache.batik.anim.values.AnimatableIntegerValue;
import org.apache.batik.anim.values.AnimatableLengthValue;
import org.apache.batik.anim.values.AnimatableLengthListValue;
import org.apache.batik.anim.values.AnimatableLengthOrIdentValue;
import org.apache.batik.anim.values.AnimatableNumberValue;
import org.apache.batik.anim.values.AnimatableNumberListValue;
import org.apache.batik.anim.values.AnimatableNumberOrPercentageValue;
import org.apache.batik.anim.values.AnimatablePathDataValue;
import org.apache.batik.anim.values.AnimatablePointListValue;
import org.apache.batik.anim.values.AnimatablePreserveAspectRatioValue;
import org.apache.batik.anim.values.AnimatableNumberOrIdentValue;
import org.apache.batik.anim.values.AnimatableRectValue;
import org.apache.batik.anim.values.AnimatableStringValue;
import org.apache.batik.anim.values.AnimatableValue;
import org.apache.batik.anim.values.AnimatableColorValue;
import org.apache.batik.anim.values.AnimatablePaintValue;
import org.apache.batik.css.engine.CSSEngine;
import org.apache.batik.css.engine.CSSStylableElement;
import org.apache.batik.css.engine.StyleMap;
import org.apache.batik.css.engine.value.FloatValue;
import org.apache.batik.css.engine.value.StringValue;
import org.apache.batik.css.engine.value.Value;
import org.apache.batik.css.engine.value.ValueManager;
import org.apache.batik.parser.DefaultPreserveAspectRatioHandler;
import org.apache.batik.parser.FloatArrayProducer;
import org.apache.batik.parser.DefaultLengthHandler;
import org.apache.batik.parser.LengthArrayProducer;
import org.apache.batik.parser.LengthHandler;
import org.apache.batik.parser.LengthListParser;
import org.apache.batik.parser.LengthParser;
import org.apache.batik.parser.NumberListParser;
import org.apache.batik.parser.PathArrayProducer;
import org.apache.batik.parser.PathParser;
import org.apache.batik.parser.PointsParser;
import org.apache.batik.parser.ParseException;
import org.apache.batik.parser.PreserveAspectRatioHandler;
import org.apache.batik.parser.PreserveAspectRatioParser;
import org.apache.batik.util.RunnableQueue;
import org.apache.batik.util.SMILConstants;
import org.apache.batik.constants.XMLConstants;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.css.CSSPrimitiveValue;
import org.w3c.dom.css.CSSStyleDeclaration;
import org.w3c.dom.css.CSSValue;
import org.w3c.dom.events.EventTarget;
import org.w3c.dom.svg.SVGAngle;
import org.w3c.dom.svg.SVGLength;
import org.w3c.dom.svg.SVGPreserveAspectRatio;

An AnimationEngine for SVG documents.
Author:Cameron McCormack
Version:$Id: SVGAnimationEngine.java 1851346 2019-01-15 13:41:00Z ssteiner $
/** * An AnimationEngine for SVG documents. * * @author <a href="mailto:cam%40mcc%2eid%2eau">Cameron McCormack</a> * @version $Id: SVGAnimationEngine.java 1851346 2019-01-15 13:41:00Z ssteiner $ */
public class SVGAnimationEngine extends AnimationEngine {
The BridgeContext to use for value parsing.
/** * The BridgeContext to use for value parsing. */
protected BridgeContext ctx;
The CSSEngine used for CSS value parsing.
/** * The CSSEngine used for CSS value parsing. */
protected CSSEngine cssEngine;
Whether animation processing has started. This affects whether animation element bridges add their animation on to the initial bridge list, or process them immediately.
/** * Whether animation processing has started. This affects whether * animation element bridges add their animation on to the initial * bridge list, or process them immediately. */
protected boolean started;
The Runnable that ticks the document.
/** * The Runnable that ticks the document. */
protected AnimationTickRunnable animationTickRunnable;
The initial time that will be seeked to when the animation engine starts, as set by setCurrentTime.
/** * The initial time that will be seeked to when the animation engine starts, * as set by {@link #setCurrentTime}. */
protected float initialStartTime;
The factory for unparsed string values.
/** * The factory for unparsed string values. */
protected UncomputedAnimatableStringValueFactory uncomputedAnimatableStringValueFactory = new UncomputedAnimatableStringValueFactory();
The factory for length-or-ident values.
/** * The factory for length-or-ident values. */
protected AnimatableLengthOrIdentFactory animatableLengthOrIdentFactory = new AnimatableLengthOrIdentFactory();
The factory for number-or-ident values.
/** * The factory for number-or-ident values. */
protected AnimatableNumberOrIdentFactory animatableNumberOrIdentFactory = new AnimatableNumberOrIdentFactory(false);
Factories for AnimatableValue parsing.
/** * Factories for {@link AnimatableValue} parsing. */
protected Factory[] factories = { null, // TYPE_UNKNOWN new AnimatableIntegerValueFactory(), // TYPE_INTEGER new AnimatableNumberValueFactory(), // TYPE_NUMBER new AnimatableLengthValueFactory(), // TYPE_LENGTH null, // TYPE_NUMBER_OPTIONAL_NUMBER new AnimatableAngleValueFactory(), // TYPE_ANGLE new AnimatableColorValueFactory(), // TYPE_COLOR new AnimatablePaintValueFactory(), // TYPE_PAINT null, // TYPE_PERCENTAGE null, // TYPE_TRANSFORM_LIST uncomputedAnimatableStringValueFactory, // TYPE_URI null, // TYPE_FREQUENCY null, // TYPE_TIME new AnimatableNumberListValueFactory(), // TYPE_NUMBER_LIST new AnimatableLengthListValueFactory(), // TYPE_LENGTH_LIST uncomputedAnimatableStringValueFactory, // TYPE_IDENT uncomputedAnimatableStringValueFactory, // TYPE_CDATA animatableLengthOrIdentFactory, // TYPE_LENGTH_OR_INHERIT uncomputedAnimatableStringValueFactory, // TYPE_IDENT_LIST uncomputedAnimatableStringValueFactory, // TYPE_CLIP_VALUE uncomputedAnimatableStringValueFactory, // TYPE_URI_OR_IDENT uncomputedAnimatableStringValueFactory, // TYPE_CURSOR_VALUE new AnimatablePathDataFactory(), // TYPE_PATH_DATA uncomputedAnimatableStringValueFactory, // TYPE_ENABLE_BACKGROUND_VALUE null, // TYPE_TIME_VALUE_LIST animatableNumberOrIdentFactory, // TYPE_NUMBER_OR_INHERIT uncomputedAnimatableStringValueFactory, // TYPE_FONT_FAMILY_VALUE null, // TYPE_FONT_FACE_FONT_SIZE_VALUE new AnimatableNumberOrIdentFactory(true), // TYPE_FONT_WEIGHT_VALUE new AnimatableAngleOrIdentFactory(), // TYPE_ANGLE_OR_IDENT null, // TYPE_KEY_SPLINES_VALUE new AnimatablePointListValueFactory(), // TYPE_POINTS_VALUE new AnimatablePreserveAspectRatioValueFactory(), // TYPE_PRESERVE_ASPECT_RATIO_VALUE null, // TYPE_URI_LIST uncomputedAnimatableStringValueFactory, // TYPE_LENGTH_LIST_OR_IDENT null, // TYPE_CHARACTER_OR_UNICODE_RANGE_LIST null, // TYPE_UNICODE_RANGE_LIST null, // TYPE_FONT_VALUE null, // TYPE_FONT_DECSRIPTOR_SRC_VALUE animatableLengthOrIdentFactory, // TYPE_FONT_SIZE_VALUE animatableLengthOrIdentFactory, // TYPE_BASELINE_SHIFT_VALUE animatableLengthOrIdentFactory, // TYPE_KERNING_VALUE animatableLengthOrIdentFactory, // TYPE_SPACING_VALUE animatableLengthOrIdentFactory, // TYPE_LINE_HEIGHT_VALUE animatableNumberOrIdentFactory, // TYPE_FONT_SIZE_ADJUST_VALUE null, // TYPE_LANG_VALUE null, // TYPE_LANG_LIST_VALUE new AnimatableNumberOrPercentageValueFactory(), // TYPE_NUMBER_OR_PERCENTAGE null, // TYPE_TIMING_SPECIFIER_LIST new AnimatableBooleanValueFactory(), // TYPE_BOOLEAN new AnimatableRectValueFactory() // TYPE_RECT };
Whether the document is an SVG 1.2 document.
/** * Whether the document is an SVG 1.2 document. */
protected boolean isSVG12;
List of bridges that will be initialized when the document is started.
/** * List of bridges that will be initialized when the document is started. */
protected LinkedList initialBridges = new LinkedList();
A StyleMap used by the Factorys when computing CSS values.
/** * A StyleMap used by the {@link Factory}s when computing CSS values. */
protected StyleMap dummyStyleMap;
The thread that ticks the animation engine.
/** * The thread that ticks the animation engine. */
protected AnimationThread animationThread;
The animation limiting mode.
/** * The animation limiting mode. */
protected int animationLimitingMode;
The amount of animation limiting.
/** * The amount of animation limiting. */
protected float animationLimitingAmount;
Set of SMIL animation event names for SVG 1.1.
/** * Set of SMIL animation event names for SVG 1.1. */
protected static final Set animationEventNames11 = new HashSet();
Set of SMIL animation event names for SVG 1.2.
/** * Set of SMIL animation event names for SVG 1.2. */
protected static final Set animationEventNames12 = new HashSet(); static { String[] eventNamesCommon = { "click", "mousedown", "mouseup", "mouseover", "mousemove", "mouseout", "beginEvent", "endEvent" }; String[] eventNamesSVG11 = { "DOMSubtreeModified", "DOMNodeInserted", "DOMNodeRemoved", "DOMNodeRemovedFromDocument", "DOMNodeInsertedIntoDocument", "DOMAttrModified", "DOMCharacterDataModified", "SVGLoad", "SVGUnload", "SVGAbort", "SVGError", "SVGResize", "SVGScroll", "repeatEvent" }; String[] eventNamesSVG12 = { "load", "resize", "scroll", "zoom" }; for (String anEventNamesCommon : eventNamesCommon) { animationEventNames11.add(anEventNamesCommon); animationEventNames12.add(anEventNamesCommon); } for (String anEventNamesSVG11 : eventNamesSVG11) { animationEventNames11.add(anEventNamesSVG11); } for (String anEventNamesSVG12 : eventNamesSVG12) { animationEventNames12.add(anEventNamesSVG12); } }
Creates a new SVGAnimationEngine.
/** * Creates a new SVGAnimationEngine. */
public SVGAnimationEngine(Document doc, BridgeContext ctx) { super(doc); this.ctx = ctx; SVGOMDocument d = (SVGOMDocument) doc; cssEngine = d.getCSSEngine(); dummyStyleMap = new StyleMap(cssEngine.getNumberOfProperties()); isSVG12 = d.isSVG12(); }
Disposes this animation engine.
/** * Disposes this animation engine. */
public void dispose() { synchronized (this) { pause(); super.dispose(); } }
Adds an animation element bridge to the list of bridges that require initializing when the document is started.
/** * Adds an animation element bridge to the list of bridges that * require initializing when the document is started. */
public void addInitialBridge(SVGAnimationElementBridge b) { if (initialBridges != null) { initialBridges.add(b); } }
Returns whether animation processing has begun.
/** * Returns whether animation processing has begun. */
public boolean hasStarted() { return started; }
Parses an AnimatableValue.
/** * Parses an AnimatableValue. */
public AnimatableValue parseAnimatableValue(Element animElt, AnimationTarget target, String ns, String ln, boolean isCSS, String s) { SVGOMElement elt = (SVGOMElement) target.getElement(); int type; if (isCSS) { type = elt.getPropertyType(ln); } else { type = elt.getAttributeType(ns, ln); } Factory factory = factories[type]; if (factory == null) { String an = ns == null ? ln : '{' + ns + '}' + ln; throw new BridgeException (ctx, animElt, "attribute.not.animatable", new Object[] { target.getElement().getNodeName(), an }); } return factories[type].createValue(target, ns, ln, isCSS, s); }
Returns an AnimatableValue for the underlying value of a CSS property.
/** * Returns an AnimatableValue for the underlying value of a CSS property. */
public AnimatableValue getUnderlyingCSSValue(Element animElt, AnimationTarget target, String pn) { ValueManager[] vms = cssEngine.getValueManagers(); int idx = cssEngine.getPropertyIndex(pn); if (idx != -1) { int type = vms[idx].getPropertyType(); Factory factory = factories[type]; if (factory == null) { throw new BridgeException (ctx, animElt, "attribute.not.animatable", new Object[] { target.getElement().getNodeName(), pn }); } SVGStylableElement e = (SVGStylableElement) target.getElement(); CSSStyleDeclaration over = e.getOverrideStyle(); String oldValue = over.getPropertyValue(pn); if (oldValue != null) { over.removeProperty(pn); } Value v = cssEngine.getComputedStyle(e, null, idx); if (oldValue != null && !oldValue.equals("")) { over.setProperty(pn, oldValue, null); } return factories[type].createValue(target, pn, v); } // XXX Doesn't handle shorthands. return null; }
Pauses the animations.
/** * Pauses the animations. */
public void pause() { super.pause(); UpdateManager um = ctx.getUpdateManager(); if (um != null) { um.getUpdateRunnableQueue().setIdleRunnable(null); } }
Pauses the animations.
/** * Pauses the animations. */
public void unpause() { super.unpause(); UpdateManager um = ctx.getUpdateManager(); if (um != null) { um.getUpdateRunnableQueue().setIdleRunnable(animationTickRunnable); } }
Returns the current document time.
/** * Returns the current document time. */
public float getCurrentTime() { boolean p = pauseTime != 0; unpause(); float t = timedDocumentRoot.getCurrentTime(); if (p) { pause(); } return Float.isNaN(t) ? 0 : t; }
Sets the current document time.
/** * Sets the current document time. */
public float setCurrentTime(float t) { if (started) { float ret = super.setCurrentTime(t); if (animationTickRunnable != null) { animationTickRunnable.resume(); } return ret; } else { initialStartTime = t; return 0; } }
Creates a new returns a new TimedDocumentRoot object for the document.
/** * Creates a new returns a new TimedDocumentRoot object for the document. */
protected TimedDocumentRoot createDocumentRoot() { return new AnimationRoot(); }
Starts the animation engine.
/** * Starts the animation engine. */
public void start(long documentStartTime) { if (started) { return; } started = true; try { try { Calendar cal = Calendar.getInstance(); cal.setTime(new Date(documentStartTime)); timedDocumentRoot.resetDocument(cal); Object[] bridges = initialBridges.toArray(); initialBridges = null; for (Object bridge2 : bridges) { SVGAnimationElementBridge bridge = (SVGAnimationElementBridge) bridge2; bridge.initializeAnimation(); } for (Object bridge1 : bridges) { SVGAnimationElementBridge bridge = (SVGAnimationElementBridge) bridge1; bridge.initializeTimedElement(); } // tick(0, false); // animationThread = new AnimationThread(); // animationThread.start(); UpdateManager um = ctx.getUpdateManager(); if (um != null) { RunnableQueue q = um.getUpdateRunnableQueue(); animationTickRunnable = new AnimationTickRunnable(q, this); q.setIdleRunnable(animationTickRunnable); if (initialStartTime != 0) { setCurrentTime(initialStartTime); } } } catch (AnimationException ex) { throw new BridgeException(ctx, ex.getElement().getElement(), ex.getMessage()); } } catch (Exception ex) { if (ctx.getUserAgent() == null) { ex.printStackTrace(); } else { ctx.getUserAgent().displayError(ex); } } }
Sets the animation limiting mode to "none".
/** * Sets the animation limiting mode to "none". */
public void setAnimationLimitingNone() { animationLimitingMode = 0; }
Sets the animation limiting mode to a percentage of CPU.
Params:
  • pc – the maximum percentage of CPU to use (0 < pc ≤ 1)
/** * Sets the animation limiting mode to a percentage of CPU. * @param pc the maximum percentage of CPU to use (0 &lt; pc ≤ 1) */
public void setAnimationLimitingCPU(float pc) { animationLimitingMode = 1; animationLimitingAmount = pc; }
Sets the animation limiting mode to a number of frames per second.
Params:
  • fps – the maximum number of frames per second (fps > 0)
/** * Sets the animation limiting mode to a number of frames per second. * @param fps the maximum number of frames per second (fps &gt; 0) */
public void setAnimationLimitingFPS(float fps) { animationLimitingMode = 2; animationLimitingAmount = fps; }
A class for the root time container.
/** * A class for the root time container. */
protected class AnimationRoot extends TimedDocumentRoot {
Creates a new AnimationRoot object.
/** * Creates a new AnimationRoot object. */
public AnimationRoot() { super(!isSVG12, isSVG12); }
Returns the namespace URI of the event that corresponds to the given animation event name.
/** * Returns the namespace URI of the event that corresponds to the given * animation event name. */
protected String getEventNamespaceURI(String eventName) { if (!isSVG12) { return null; } if (eventName.equals("focusin") || eventName.equals("focusout") || eventName.equals("activate") || animationEventNames12.contains(eventName)) { return XMLConstants.XML_EVENTS_NAMESPACE_URI; } return null; }
Returns the type of the event that corresponds to the given animation event name.
/** * Returns the type of the event that corresponds to the given * animation event name. */
protected String getEventType(String eventName) { if (eventName.equals("focusin")) { return "DOMFocusIn"; } else if (eventName.equals("focusout")) { return "DOMFocusOut"; } else if (eventName.equals("activate")) { return "DOMActivate"; } if (isSVG12) { if (animationEventNames12.contains(eventName)) { return eventName; } } else { if (animationEventNames11.contains(eventName)) { return eventName; } } return null; }
Returns the name of the repeat event.
Returns:"repeatEvent" for SVG
/** * Returns the name of the repeat event. * @return "repeatEvent" for SVG */
protected String getRepeatEventName() { return SMILConstants.SMIL_REPEAT_EVENT_NAME; }
Fires a TimeEvent of the given type on this element.
Params:
  • eventType – the type of TimeEvent ("beginEvent", "endEvent" or "repeatEvent"/"repeat").
  • time – the timestamp of the event object
/** * Fires a TimeEvent of the given type on this element. * @param eventType the type of TimeEvent ("beginEvent", "endEvent" * or "repeatEvent"/"repeat"). * @param time the timestamp of the event object */
protected void fireTimeEvent(String eventType, Calendar time, int detail) { AnimationSupport.fireTimeEvent ((EventTarget) document, eventType, time, detail); }
Invoked to indicate this timed element became active at the specified time.
Params:
  • begin – the time the element became active, in document simple time
/** * Invoked to indicate this timed element became active at the * specified time. * @param begin the time the element became active, in document simple time */
protected void toActive(float begin) { }
Invoked to indicate that this timed element became inactive.
Params:
  • stillActive – if true, indicates that the element is still actually active, but between the end of the computed repeat duration and the end of the interval
  • isFrozen – whether the element is frozen or not
/** * Invoked to indicate that this timed element became inactive. * @param stillActive if true, indicates that the element is still * actually active, but between the end of the * computed repeat duration and the end of the * interval * @param isFrozen whether the element is frozen or not */
protected void toInactive(boolean stillActive, boolean isFrozen) { }
Invoked to indicate that this timed element has had its fill removed.
/** * Invoked to indicate that this timed element has had its fill removed. */
protected void removeFill() { }
Invoked to indicate that this timed element has been sampled at the given time.
Params:
  • simpleTime – the sample time in local simple time
  • simpleDur – the simple duration of the element
  • repeatIteration – the repeat iteration during which the element was sampled
/** * Invoked to indicate that this timed element has been sampled at the * given time. * @param simpleTime the sample time in local simple time * @param simpleDur the simple duration of the element * @param repeatIteration the repeat iteration during which the element * was sampled */
protected void sampledAt(float simpleTime, float simpleDur, int repeatIteration) { }
Invoked to indicate that this timed element has been sampled at the end of its active time, at an integer multiple of the simple duration. This is the "last" value that will be used for filling, which cannot be sampled normally.
/** * Invoked to indicate that this timed element has been sampled * at the end of its active time, at an integer multiple of the * simple duration. This is the "last" value that will be used * for filling, which cannot be sampled normally. */
protected void sampledLastValue(int repeatIteration) { }
Returns the timed element with the given ID.
/** * Returns the timed element with the given ID. */
protected TimedElement getTimedElementById(String id) { return AnimationSupport.getTimedElementById(id, document); }
Returns the event target with the given ID.
/** * Returns the event target with the given ID. */
protected EventTarget getEventTargetById(String id) { return AnimationSupport.getEventTargetById(id, document); }
Returns the target of this animation as an EventTarget. Used for eventbase timing specifiers where the element ID is omitted.
/** * Returns the target of this animation as an {@link EventTarget}. Used * for eventbase timing specifiers where the element ID is omitted. */
protected EventTarget getAnimationEventTarget() { return null; }
Returns the event target that should be listened to for access key events.
/** * Returns the event target that should be listened to for * access key events. */
protected EventTarget getRootEventTarget() { return (EventTarget) document; }
Returns the DOM element that corresponds to this timed element, if such a DOM element exists.
/** * Returns the DOM element that corresponds to this timed element, if * such a DOM element exists. */
public Element getElement() { return null; }
Returns whether this timed element comes before the given timed element in document order.
/** * Returns whether this timed element comes before the given timed * element in document order. */
public boolean isBefore(TimedElement other) { return false; }
Invoked by timed elements in this document to indicate that the current interval will be re-evaluated at the next sample.
/** * Invoked by timed elements in this document to indicate that the * current interval will be re-evaluated at the next sample. */
protected void currentIntervalWillUpdate() { if (animationTickRunnable != null) { animationTickRunnable.resume(); } } }
Idle runnable to tick the animation, that reads times from System.in.
/** * Idle runnable to tick the animation, that reads times from System.in. */
protected static class DebugAnimationTickRunnable extends AnimationTickRunnable { float t = 0f; public DebugAnimationTickRunnable(RunnableQueue q, SVGAnimationEngine eng) { super(q, eng); waitTime = Long.MAX_VALUE; new Thread() { public void run() { java.io.BufferedReader r = new java.io.BufferedReader(new java.io.InputStreamReader(System.in)); System.out.println("Enter times."); for (;;) { String s; try { s = r.readLine(); } catch (java.io.IOException e) { s = null; } if (s == null) { System.exit(0); } t = Float.parseFloat(s); DebugAnimationTickRunnable.this.resume(); } } }.start(); } public void resume() { waitTime = 0; Object lock = q.getIteratorLock(); synchronized (lock) { lock.notify(); } } public long getWaitTime() { long wt = waitTime; waitTime = Long.MAX_VALUE; return wt; } public void run() { SVGAnimationEngine eng = getAnimationEngine(); synchronized (eng) { try { try { eng.tick(t, false); } catch (AnimationException ex) { throw new BridgeException (eng.ctx, ex.getElement().getElement(), ex.getMessage()); } } catch (Exception ex) { if (eng.ctx.getUserAgent() == null) { ex.printStackTrace(); } else { eng.ctx.getUserAgent().displayError(ex); } } } } }
Idle runnable to tick the animation.
/** * Idle runnable to tick the animation. */
protected static class AnimationTickRunnable implements RunnableQueue.IdleRunnable {
Calendar instance used for passing current time values to the animation timing system.
/** * Calendar instance used for passing current time values to the * animation timing system. */
protected Calendar time = Calendar.getInstance(); // /** // * The current document time in seconds, truncated. // */ // protected double second = -1.; // /** // * The number of frames that have been ticked so far this second. // */ // protected int frames;
The number of milliseconds to wait until the next animation tick. This is returned by getWaitTime().
/** * The number of milliseconds to wait until the next animation tick. * This is returned by {@link #getWaitTime()}. */
protected long waitTime;
The RunnableQueue in which this is the IdleRunnable.
/** * The RunnableQueue in which this is the * {@link RunnableQueue.IdleRunnable}. */
protected RunnableQueue q;
The number of past tick times to keep, for computing the average time per tick.
/** * The number of past tick times to keep, for computing the average * time per tick. */
private static final int NUM_TIMES = 8;
The past tick times.
/** * The past tick times. */
protected long[] times = new long[NUM_TIMES];
The sum of the times in times.
/** * The sum of the times in {@link #times}. */
protected long sumTime;
The current index into times.
/** * The current index into {@link #times}. */
protected int timeIndex;
A weak reference to the SVGAnimationEngine this AnimationTickRunnable is for. We make this a WeakReference so that a ticking animation engine does not prevent from being GCed.
/** * A weak reference to the SVGAnimationEngine this AnimationTickRunnable * is for. We make this a WeakReference so that a ticking animation * engine does not prevent from being GCed. */
protected WeakReference engRef;
The maximum number of consecutive exceptions to allow before stopping the report of them.
/** * The maximum number of consecutive exceptions to allow before * stopping the report of them. */
protected static final int MAX_EXCEPTION_COUNT = 10;
The number of consecutive exceptions that have been thrown. This is used to detect when exceptions are occurring every tick, and to stop reporting them when this happens.
/** * The number of consecutive exceptions that have been thrown. This is * used to detect when exceptions are occurring every tick, and to stop * reporting them when this happens. */
protected int exceptionCount;
Creates a new AnimationTickRunnable.
/** * Creates a new AnimationTickRunnable. */
public AnimationTickRunnable(RunnableQueue q, SVGAnimationEngine eng) { this.q = q; this.engRef = new WeakReference(eng); // Initialize the past times to 100ms. Arrays.fill(times, 100); sumTime = 100 * NUM_TIMES; }
Forces an animation update, if the RunnableQueue is currently waiting.
/** * Forces an animation update, if the {@link RunnableQueue} is * currently waiting. */
public void resume() { waitTime = 0; Object lock = q.getIteratorLock(); synchronized (lock) { lock.notify(); } }
Returns the system time that can be safely waited until before this Runnable is run again.
Returns:time to wait until, 0 if no waiting can be done, or Long.MAX_VALUE if the Runnable should not be run again at this time
/** * Returns the system time that can be safely waited until before this * {@link Runnable} is run again. * * @return time to wait until, <code>0</code> if no waiting can * be done, or {@link Long#MAX_VALUE} if the {@link Runnable} * should not be run again at this time */
public long getWaitTime() { return waitTime; }
Performs one tick of the animation.
/** * Performs one tick of the animation. */
public void run() { SVGAnimationEngine eng = getAnimationEngine(); synchronized (eng) { int animationLimitingMode = eng.animationLimitingMode; float animationLimitingAmount = eng.animationLimitingAmount; try { try { long before = System.currentTimeMillis(); time.setTime(new Date(before)); float t = eng.timedDocumentRoot.convertWallclockTime(time); // if (Math.floor(t) > second) { // second = Math.floor(t); // System.err.println("fps: " + frames); // frames = 0; // } float t2 = eng.tick(t, false); long after = System.currentTimeMillis(); long dur = after - before; if (dur == 0) { dur = 1; } sumTime -= times[timeIndex]; sumTime += dur; times[timeIndex] = dur; timeIndex = (timeIndex + 1) % NUM_TIMES; if (t2 == Float.POSITIVE_INFINITY) { waitTime = Long.MAX_VALUE; } else { waitTime = before + (long) (t2 * 1000) - 1000; if (waitTime < after) { waitTime = after; } if (animationLimitingMode != 0) { float ave = (float) sumTime / NUM_TIMES; float delay; if (animationLimitingMode == 1) { // %cpu delay = ave / animationLimitingAmount - ave; } else { // fps delay = 1000f / animationLimitingAmount - ave; } long newWaitTime = after + (long) delay; if (newWaitTime > waitTime) { waitTime = newWaitTime; } } } // frames++; } catch (AnimationException ex) { throw new BridgeException (eng.ctx, ex.getElement().getElement(), ex.getMessage()); } exceptionCount = 0; } catch (Exception ex) { if (++exceptionCount < MAX_EXCEPTION_COUNT) { if (eng.ctx.getUserAgent() == null) { ex.printStackTrace(); } else { eng.ctx.getUserAgent().displayError(ex); } } } if (animationLimitingMode == 0) { // so we don't steal too much time from the Swing thread try { Thread.sleep(1); } catch (InterruptedException ie) { } } } }
Returns the SVGAnimationEngine this AnimationTickRunnable is for.
/** * Returns the SVGAnimationEngine this AnimationTickRunnable is for. */
protected SVGAnimationEngine getAnimationEngine() { return (SVGAnimationEngine) engRef.get(); } }
The thread that ticks the animation.
/** * The thread that ticks the animation. */
protected class AnimationThread extends Thread {
The current time.
/** * The current time. */
protected Calendar time = Calendar.getInstance();
The RunnableQueue to perform the animation in.
/** * The RunnableQueue to perform the animation in. */
protected RunnableQueue runnableQueue = ctx.getUpdateManager().getUpdateRunnableQueue();
The animation ticker Runnable.
/** * The animation ticker Runnable. */
protected Ticker ticker = new Ticker();
Ticks the animation over as fast as possible.
/** * Ticks the animation over as fast as possible. */
public void run() { if (true) { for (;;) { time.setTime(new Date()); ticker.t = timedDocumentRoot.convertWallclockTime(time); try { runnableQueue.invokeAndWait(ticker); } catch (InterruptedException e) { return; } } } else { ticker.t = 1; while (ticker.t < 10) { try { Thread.sleep(1000); } catch (InterruptedException ie) { } try { runnableQueue.invokeAndWait(ticker); } catch (InterruptedException e) { return; } ticker.t++; } } }
A runnable that ticks the animation engine.
/** * A runnable that ticks the animation engine. */
protected class Ticker implements Runnable {
The document time to tick at next.
/** * The document time to tick at next. */
protected float t;
Ticks the animation over.
/** * Ticks the animation over. */
public void run() { tick(t, false); } } } // AnimatableValue factories
Interface for AnimatableValue factories.
/** * Interface for AnimatableValue factories. */
protected interface Factory {
Creates a new AnimatableValue from a string.
/** * Creates a new AnimatableValue from a string. */
AnimatableValue createValue(AnimationTarget target, String ns, String ln, boolean isCSS, String s);
Creates a new AnimatableValue from a CSS Value.
/** * Creates a new AnimatableValue from a CSS {@link Value}. */
AnimatableValue createValue(AnimationTarget target, String pn, Value v); }
Factory class for AnimatableValues for CSS properties. XXX Shorthand properties are not supported.
/** * Factory class for AnimatableValues for CSS properties. * XXX Shorthand properties are not supported. */
protected abstract class CSSValueFactory implements Factory { public AnimatableValue createValue(AnimationTarget target, String ns, String ln, boolean isCSS, String s) { // XXX Always parsing as a CSS value. return createValue(target, ln, createCSSValue(target, ln, s)); } public AnimatableValue createValue(AnimationTarget target, String pn, Value v) { CSSStylableElement elt = (CSSStylableElement) target.getElement(); v = computeValue(elt, pn, v); return createAnimatableValue(target, pn, v); }
Creates a new AnimatableValue from a CSS Value, after computation and inheritance.
/** * Creates a new AnimatableValue from a CSS {@link Value}, after * computation and inheritance. */
protected abstract AnimatableValue createAnimatableValue (AnimationTarget target, String pn, Value v);
Creates a new CSS Value from a string.
/** * Creates a new CSS {@link Value} from a string. */
protected Value createCSSValue(AnimationTarget t, String pn, String s) { CSSStylableElement elt = (CSSStylableElement) t.getElement(); Value v = cssEngine.parsePropertyValue(elt, pn, s); return computeValue(elt, pn, v); }
Computes a CSS Value and performance inheritance if the specified value is 'inherit'.
/** * Computes a CSS {@link Value} and performance inheritance if the * specified value is 'inherit'. */
protected Value computeValue(CSSStylableElement elt, String pn, Value v) { ValueManager[] vms = cssEngine.getValueManagers(); int idx = cssEngine.getPropertyIndex(pn); if (idx != -1) { if (v.getCssValueType() == CSSValue.CSS_INHERIT) { elt = CSSEngine.getParentCSSStylableElement(elt); if (elt != null) { return cssEngine.getComputedStyle(elt, null, idx); } return vms[idx].getDefaultValue(); } v = vms[idx].computeValue(elt, null, cssEngine, idx, dummyStyleMap, v); } return v; } }
Factory class for AnimatableBooleanValues.
/** * Factory class for {@link AnimatableBooleanValue}s. */
protected static class AnimatableBooleanValueFactory implements Factory {
Creates a new AnimatableValue from a string.
/** * Creates a new AnimatableValue from a string. */
public AnimatableValue createValue(AnimationTarget target, String ns, String ln, boolean isCSS, String s) { return new AnimatableBooleanValue(target, "true".equals(s)); }
Creates a new AnimatableValue from a CSS Value.
/** * Creates a new AnimatableValue from a CSS {@link Value}. */
public AnimatableValue createValue(AnimationTarget target, String pn, Value v) { return new AnimatableBooleanValue(target, "true".equals(v.getCssText())); } }
Factory class for AnimatableIntegerValues.
/** * Factory class for {@link AnimatableIntegerValue}s. */
protected static class AnimatableIntegerValueFactory implements Factory {
Creates a new AnimatableValue from a string.
/** * Creates a new AnimatableValue from a string. */
public AnimatableValue createValue(AnimationTarget target, String ns, String ln, boolean isCSS, String s) { return new AnimatableIntegerValue(target, Integer.parseInt(s)); }
Creates a new AnimatableValue from a CSS Value.
/** * Creates a new AnimatableValue from a CSS {@link Value}. */
public AnimatableValue createValue(AnimationTarget target, String pn, Value v) { return new AnimatableIntegerValue(target, Math.round(v.getFloatValue())); } }
Factory class for AnimatableNumberValues.
/** * Factory class for {@link AnimatableNumberValue}s. */
protected static class AnimatableNumberValueFactory implements Factory {
Creates a new AnimatableValue from a string.
/** * Creates a new AnimatableValue from a string. */
public AnimatableValue createValue(AnimationTarget target, String ns, String ln, boolean isCSS, String s) { return new AnimatableNumberValue(target, Float.parseFloat(s)); }
Creates a new AnimatableValue from a CSS Value.
/** * Creates a new AnimatableValue from a CSS {@link Value}. */
public AnimatableValue createValue(AnimationTarget target, String pn, Value v) { return new AnimatableNumberValue(target, v.getFloatValue()); } } /** * Factory class for {@link AnimatableNumberOrPercentageValue}s. */ protected static class AnimatableNumberOrPercentageValueFactory implements Factory {
Creates a new AnimatableValue from a string.
/** * Creates a new AnimatableValue from a string. */
public AnimatableValue createValue(AnimationTarget target, String ns, String ln, boolean isCSS, String s) { float v; boolean pc; if (s.charAt(s.length() - 1) == '%') { v = Float.parseFloat(s.substring(0, s.length() - 1)); pc = true; } else { v = Float.parseFloat(s); pc = false; } return new AnimatableNumberOrPercentageValue(target, v, pc); }
Creates a new AnimatableValue from a CSS Value.
/** * Creates a new AnimatableValue from a CSS {@link Value}. */
public AnimatableValue createValue(AnimationTarget target, String pn, Value v) { switch (v.getPrimitiveType()) { case CSSPrimitiveValue.CSS_PERCENTAGE: return new AnimatableNumberOrPercentageValue (target, v.getFloatValue(), true); case CSSPrimitiveValue.CSS_NUMBER: return new AnimatableNumberOrPercentageValue (target, v.getFloatValue()); } // XXX Do something better than returning null. return null; } } /** * Factory class for {@link AnimatablePreserveAspectRatioValue}s. */ protected static class AnimatablePreserveAspectRatioValueFactory implements Factory {
The parsed 'align' value.
/** * The parsed 'align' value. */
protected short align;
The parsed 'meetOrSlice' value.
/** * The parsed 'meetOrSlice' value. */
protected short meetOrSlice;
Parser for preserveAspectRatio values.
/** * Parser for preserveAspectRatio values. */
protected PreserveAspectRatioParser parser = new PreserveAspectRatioParser();
Handler for the preserveAspectRatio parser.
/** * Handler for the preserveAspectRatio parser. */
protected DefaultPreserveAspectRatioHandler handler = new DefaultPreserveAspectRatioHandler() { /** * Implements {@link * PreserveAspectRatioHandler#startPreserveAspectRatio()}. */ public void startPreserveAspectRatio() throws ParseException { align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_UNKNOWN; meetOrSlice = SVGPreserveAspectRatio.SVG_MEETORSLICE_UNKNOWN; } /** * Implements {@link PreserveAspectRatioHandler#none()}. */ public void none() throws ParseException { align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_NONE; } /** * Implements {@link PreserveAspectRatioHandler#xMaxYMax()}. */ public void xMaxYMax() throws ParseException { align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMAX; } /** * Implements {@link PreserveAspectRatioHandler#xMaxYMid()}. */ public void xMaxYMid() throws ParseException { align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMID; } /** * Implements {@link PreserveAspectRatioHandler#xMaxYMin()}. */ public void xMaxYMin() throws ParseException { align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMAXYMIN; } /** * Implements {@link PreserveAspectRatioHandler#xMidYMax()}. */ public void xMidYMax() throws ParseException { align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMAX; } /** * Implements {@link PreserveAspectRatioHandler#xMidYMid()}. */ public void xMidYMid() throws ParseException { align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMID; } /** * Implements {@link PreserveAspectRatioHandler#xMidYMin()}. */ public void xMidYMin() throws ParseException { align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMIDYMIN; } /** * Implements {@link PreserveAspectRatioHandler#xMinYMax()}. */ public void xMinYMax() throws ParseException { align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMAX; } /** * Implements {@link PreserveAspectRatioHandler#xMinYMid()}. */ public void xMinYMid() throws ParseException { align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMID; } /** * Implements {@link PreserveAspectRatioHandler#xMinYMin()}. */ public void xMinYMin() throws ParseException { align = SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN; } /** * Implements {@link PreserveAspectRatioHandler#meet()}. */ public void meet() throws ParseException { meetOrSlice = SVGPreserveAspectRatio.SVG_MEETORSLICE_MEET; } /** * Implements {@link PreserveAspectRatioHandler#slice()}. */ public void slice() throws ParseException { meetOrSlice = SVGPreserveAspectRatio.SVG_MEETORSLICE_SLICE; } };
Creates a new AnimatablePreserveAspectRatioValueFactory.
/** * Creates a new AnimatablePreserveAspectRatioValueFactory. */
public AnimatablePreserveAspectRatioValueFactory() { parser.setPreserveAspectRatioHandler(handler); }
Creates a new AnimatableValue from a string.
/** * Creates a new AnimatableValue from a string. */
public AnimatableValue createValue(AnimationTarget target, String ns, String ln, boolean isCSS, String s) { try { parser.parse(s); return new AnimatablePreserveAspectRatioValue(target, align, meetOrSlice); } catch (ParseException e) { // XXX Do something better than returning null. return null; } }
Creates a new AnimatableValue from a CSS Value. Returns null since preserveAspectRatio values aren't used in CSS values.
/** * Creates a new AnimatableValue from a CSS {@link Value}. Returns null * since preserveAspectRatio values aren't used in CSS values. */
public AnimatableValue createValue(AnimationTarget target, String pn, Value v) { return null; } }
Factory class for AnimatableLengthValues.
/** * Factory class for {@link AnimatableLengthValue}s. */
protected static class AnimatableLengthValueFactory implements Factory {
The parsed length unit type.
/** * The parsed length unit type. */
protected short type;
The parsed length value.
/** * The parsed length value. */
protected float value;
Parser for lengths.
/** * Parser for lengths. */
protected LengthParser parser = new LengthParser();
Handler for the length parser.
/** * Handler for the length parser. */
protected LengthHandler handler = new DefaultLengthHandler() { public void startLength() throws ParseException { type = SVGLength.SVG_LENGTHTYPE_NUMBER; } public void lengthValue(float v) throws ParseException { value = v; } public void em() throws ParseException { type = SVGLength.SVG_LENGTHTYPE_EMS; } public void ex() throws ParseException { type = SVGLength.SVG_LENGTHTYPE_EXS; } public void in() throws ParseException { type = SVGLength.SVG_LENGTHTYPE_IN; } public void cm() throws ParseException { type = SVGLength.SVG_LENGTHTYPE_CM; } public void mm() throws ParseException { type = SVGLength.SVG_LENGTHTYPE_MM; } public void pc() throws ParseException { type = SVGLength.SVG_LENGTHTYPE_PC; } public void pt() throws ParseException { type = SVGLength.SVG_LENGTHTYPE_PT; } public void px() throws ParseException { type = SVGLength.SVG_LENGTHTYPE_PX; } public void percentage() throws ParseException { type = SVGLength.SVG_LENGTHTYPE_PERCENTAGE; } public void endLength() throws ParseException { } };
Creates a new AnimatableLengthValueFactory.
/** * Creates a new AnimatableLengthValueFactory. */
public AnimatableLengthValueFactory() { parser.setLengthHandler(handler); }
Creates a new AnimatableValue from a string.
/** * Creates a new AnimatableValue from a string. */
public AnimatableValue createValue(AnimationTarget target, String ns, String ln, boolean isCSS, String s) { short pcInterp = target.getPercentageInterpretation(ns, ln, isCSS); try { parser.parse(s); return new AnimatableLengthValue (target, type, value, pcInterp); } catch (ParseException e) { // XXX Do something better than returning null. return null; } }
Creates a new AnimatableValue from a CSS Value.
/** * Creates a new AnimatableValue from a CSS {@link Value}. */
public AnimatableValue createValue(AnimationTarget target, String pn, Value v) { return new AnimatableIntegerValue(target, Math.round(v.getFloatValue())); } }
Factory class for AnimatableLengthListValues.
/** * Factory class for {@link AnimatableLengthListValue}s. */
protected static class AnimatableLengthListValueFactory implements Factory {
Parser for length lists.
/** * Parser for length lists. */
protected LengthListParser parser = new LengthListParser();
The producer class that accumulates the lengths.
/** * The producer class that accumulates the lengths. */
protected LengthArrayProducer producer = new LengthArrayProducer();
Creates a new AnimatableLengthListValueFactory.
/** * Creates a new AnimatableLengthListValueFactory. */
public AnimatableLengthListValueFactory() { parser.setLengthListHandler(producer); }
Creates a new AnimatableValue from a string.
/** * Creates a new AnimatableValue from a string. */
public AnimatableValue createValue(AnimationTarget target, String ns, String ln, boolean isCSS, String s) { try { short pcInterp = target.getPercentageInterpretation (ns, ln, isCSS); parser.parse(s); return new AnimatableLengthListValue (target, producer.getLengthTypeArray(), producer.getLengthValueArray(), pcInterp); } catch (ParseException e) { // XXX Do something better than returning null. return null; } }
Creates a new AnimatableValue from a CSS Value. Returns null since point lists aren't used in CSS values.
/** * Creates a new AnimatableValue from a CSS {@link Value}. Returns null * since point lists aren't used in CSS values. */
public AnimatableValue createValue(AnimationTarget target, String pn, Value v) { return null; } }
Factory class for AnimatableNumberListValues.
/** * Factory class for {@link AnimatableNumberListValue}s. */
protected static class AnimatableNumberListValueFactory implements Factory {
Parser for number lists.
/** * Parser for number lists. */
protected NumberListParser parser = new NumberListParser();
The producer class that accumulates the numbers.
/** * The producer class that accumulates the numbers. */
protected FloatArrayProducer producer = new FloatArrayProducer();
Creates a new AnimatableNumberListValueFactory.
/** * Creates a new AnimatableNumberListValueFactory. */
public AnimatableNumberListValueFactory() { parser.setNumberListHandler(producer); }
Creates a new AnimatableValue from a string.
/** * Creates a new AnimatableValue from a string. */
public AnimatableValue createValue(AnimationTarget target, String ns, String ln, boolean isCSS, String s) { try { parser.parse(s); return new AnimatableNumberListValue(target, producer.getFloatArray()); } catch (ParseException e) { // XXX Do something better than returning null. return null; } }
Creates a new AnimatableValue from a CSS Value. Returns null since number lists aren't used in CSS values.
/** * Creates a new AnimatableValue from a CSS {@link Value}. Returns null * since number lists aren't used in CSS values. */
public AnimatableValue createValue(AnimationTarget target, String pn, Value v) { return null; } }
Factory class for AnimatableNumberListValues.
/** * Factory class for {@link AnimatableNumberListValue}s. */
protected static class AnimatableRectValueFactory implements Factory {
Parser for number lists.
/** * Parser for number lists. */
protected NumberListParser parser = new NumberListParser();
The producer class that accumulates the numbers.
/** * The producer class that accumulates the numbers. */
protected FloatArrayProducer producer = new FloatArrayProducer();
Creates a new AnimatableNumberListValueFactory.
/** * Creates a new AnimatableNumberListValueFactory. */
public AnimatableRectValueFactory() { parser.setNumberListHandler(producer); }
Creates a new AnimatableValue from a string.
/** * Creates a new AnimatableValue from a string. */
public AnimatableValue createValue(AnimationTarget target, String ns, String ln, boolean isCSS, String s) { try { parser.parse(s); float[] r = producer.getFloatArray(); if (r.length != 4) { // XXX Do something better than returning null. return null; } return new AnimatableRectValue(target, r[0], r[1], r[2], r[3]); } catch (ParseException e) { // XXX Do something better than returning null. return null; } }
Creates a new AnimatableValue from a CSS Value. Returns null since rects aren't used in CSS values.
/** * Creates a new AnimatableValue from a CSS {@link Value}. Returns null * since rects aren't used in CSS values. */
public AnimatableValue createValue(AnimationTarget target, String pn, Value v) { return null; } }
Factory class for AnimatablePointListValues.
/** * Factory class for {@link AnimatablePointListValue}s. */
protected static class AnimatablePointListValueFactory implements Factory {
Parser for point lists.
/** * Parser for point lists. */
protected PointsParser parser = new PointsParser();
The producer class that accumulates the points.
/** * The producer class that accumulates the points. */
protected FloatArrayProducer producer = new FloatArrayProducer();
Creates a new AnimatablePointListValueFactory.
/** * Creates a new AnimatablePointListValueFactory. */
public AnimatablePointListValueFactory() { parser.setPointsHandler(producer); }
Creates a new AnimatableValue from a string.
/** * Creates a new AnimatableValue from a string. */
public AnimatableValue createValue(AnimationTarget target, String ns, String ln, boolean isCSS, String s) { try { parser.parse(s); return new AnimatablePointListValue(target, producer.getFloatArray()); } catch (ParseException e) { // XXX Do something better than returning null. return null; } }
Creates a new AnimatableValue from a CSS Value. Returns null since point lists aren't used in CSS values.
/** * Creates a new AnimatableValue from a CSS {@link Value}. Returns null * since point lists aren't used in CSS values. */
public AnimatableValue createValue(AnimationTarget target, String pn, Value v) { return null; } }
Factory class for AnimatablePathDataValues.
/** * Factory class for {@link AnimatablePathDataValue}s. */
protected static class AnimatablePathDataFactory implements Factory {
Parser for path data.
/** * Parser for path data. */
protected PathParser parser = new PathParser();
The producer class that accumulates the path segments.
/** * The producer class that accumulates the path segments. */
protected PathArrayProducer producer = new PathArrayProducer();
Creates a new AnimatablePathDataFactory.
/** * Creates a new AnimatablePathDataFactory. */
public AnimatablePathDataFactory() { parser.setPathHandler(producer); }
Creates a new AnimatableValue from a string.
/** * Creates a new AnimatableValue from a string. */
public AnimatableValue createValue(AnimationTarget target, String ns, String ln, boolean isCSS, String s) { try { parser.parse(s); return new AnimatablePathDataValue (target, producer.getPathCommands(), producer.getPathParameters()); } catch (ParseException e) { // XXX Do something better than returning null. return null; } }
Creates a new AnimatableValue from a CSS Value. Returns null since point lists aren't used in CSS values.
/** * Creates a new AnimatableValue from a CSS {@link Value}. Returns null * since point lists aren't used in CSS values. */
public AnimatableValue createValue(AnimationTarget target, String pn, Value v) { return null; } }
Factory class for AnimatableStringValues.
/** * Factory class for {@link AnimatableStringValue}s. */
protected static class UncomputedAnimatableStringValueFactory implements Factory { public AnimatableValue createValue(AnimationTarget target, String ns, String ln, boolean isCSS, String s) { return new AnimatableStringValue(target, s); } public AnimatableValue createValue(AnimationTarget target, String pn, Value v) { return new AnimatableStringValue(target, v.getCssText()); } }
Factory class for AnimatableLengthOrIdentValues.
/** * Factory class for {@link AnimatableLengthOrIdentValue}s. */
protected class AnimatableLengthOrIdentFactory extends CSSValueFactory { protected AnimatableValue createAnimatableValue(AnimationTarget target, String pn, Value v) { if (v instanceof StringValue) { return new AnimatableLengthOrIdentValue(target, v.getStringValue()); } short pcInterp = target.getPercentageInterpretation(null, pn, true); FloatValue fv = (FloatValue) v; return new AnimatableLengthOrIdentValue (target, fv.getPrimitiveType(), fv.getFloatValue(), pcInterp); } }
Factory class for AnimatableNumberOrIdentValues.
/** * Factory class for {@link AnimatableNumberOrIdentValue}s. */
protected class AnimatableNumberOrIdentFactory extends CSSValueFactory {
Whether numbers are actually numeric keywords, as with the font-weight property.
/** * Whether numbers are actually numeric keywords, as with the * font-weight property. */
protected boolean numericIdents; public AnimatableNumberOrIdentFactory(boolean numericIdents) { this.numericIdents = numericIdents; } protected AnimatableValue createAnimatableValue(AnimationTarget target, String pn, Value v) { if (v instanceof StringValue) { return new AnimatableNumberOrIdentValue(target, v.getStringValue()); } FloatValue fv = (FloatValue) v; return new AnimatableNumberOrIdentValue(target, fv.getFloatValue(), numericIdents); } }
Factory class for AnimatableAngleValues.
/** * Factory class for {@link AnimatableAngleValue}s. */
protected class AnimatableAngleValueFactory extends CSSValueFactory { protected AnimatableValue createAnimatableValue(AnimationTarget target, String pn, Value v) { FloatValue fv = (FloatValue) v; short unit; switch (fv.getPrimitiveType()) { case CSSPrimitiveValue.CSS_NUMBER: case CSSPrimitiveValue.CSS_DEG: unit = SVGAngle.SVG_ANGLETYPE_DEG; break; case CSSPrimitiveValue.CSS_RAD: unit = SVGAngle.SVG_ANGLETYPE_RAD; break; case CSSPrimitiveValue.CSS_GRAD: unit = SVGAngle.SVG_ANGLETYPE_GRAD; break; default: // XXX Do something better than returning null. return null; } return new AnimatableAngleValue(target, fv.getFloatValue(), unit); } }
Factory class for AnimatableAngleOrIdentValues.
/** * Factory class for {@link AnimatableAngleOrIdentValue}s. */
protected class AnimatableAngleOrIdentFactory extends CSSValueFactory { protected AnimatableValue createAnimatableValue(AnimationTarget target, String pn, Value v) { if (v instanceof StringValue) { return new AnimatableAngleOrIdentValue(target, v.getStringValue()); } FloatValue fv = (FloatValue) v; short unit; switch (fv.getPrimitiveType()) { case CSSPrimitiveValue.CSS_NUMBER: case CSSPrimitiveValue.CSS_DEG: unit = SVGAngle.SVG_ANGLETYPE_DEG; break; case CSSPrimitiveValue.CSS_RAD: unit = SVGAngle.SVG_ANGLETYPE_RAD; break; case CSSPrimitiveValue.CSS_GRAD: unit = SVGAngle.SVG_ANGLETYPE_GRAD; break; default: // XXX Do something better than returning null. return null; } return new AnimatableAngleOrIdentValue(target, fv.getFloatValue(), unit); } }
Factory class for AnimatableColorValues.
/** * Factory class for {@link AnimatableColorValue}s. */
protected class AnimatableColorValueFactory extends CSSValueFactory { protected AnimatableValue createAnimatableValue(AnimationTarget target, String pn, Value v) { Paint p = PaintServer.convertPaint (target.getElement(), null, v, 1.0f, ctx); if (p instanceof Color) { Color c = (Color) p; return new AnimatableColorValue(target, c.getRed() / 255f, c.getGreen() / 255f, c.getBlue() / 255f); } // XXX Indicate that the parsed value wasn't a Color? return null; } }
Factory class for AnimatablePaintValues.
/** * Factory class for {@link AnimatablePaintValue}s. */
protected class AnimatablePaintValueFactory extends CSSValueFactory {
Creates a new AnimatablePaintValue from a Color object.
/** * Creates a new {@link AnimatablePaintValue} from a {@link Color} * object. */
protected AnimatablePaintValue createColorPaintValue(AnimationTarget t, Color c) { return AnimatablePaintValue.createColorPaintValue (t, c.getRed() / 255f, c.getGreen() / 255f, c.getBlue() / 255f); } protected AnimatableValue createAnimatableValue(AnimationTarget target, String pn, Value v) { if (v.getCssValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { switch (v.getPrimitiveType()) { case CSSPrimitiveValue.CSS_IDENT: return AnimatablePaintValue.createNonePaintValue(target); case CSSPrimitiveValue.CSS_RGBCOLOR: { Paint p = PaintServer.convertPaint (target.getElement(), null, v, 1.0f, ctx); return createColorPaintValue(target, (Color) p); } case CSSPrimitiveValue.CSS_URI: return AnimatablePaintValue.createURIPaintValue (target, v.getStringValue()); } } else { Value v1 = v.item(0); switch (v1.getPrimitiveType()) { case CSSPrimitiveValue.CSS_RGBCOLOR: { Paint p = PaintServer.convertPaint (target.getElement(), null, v, 1.0f, ctx); return createColorPaintValue(target, (Color) p); } case CSSPrimitiveValue.CSS_URI: { Value v2 = v.item(1); switch (v2.getPrimitiveType()) { case CSSPrimitiveValue.CSS_IDENT: return AnimatablePaintValue.createURINonePaintValue (target, v1.getStringValue()); case CSSPrimitiveValue.CSS_RGBCOLOR: { Paint p = PaintServer.convertPaint (target.getElement(), null, v.item(1), 1.0f, ctx); return createColorPaintValue(target, (Color) p); } } } } } // XXX Indicate that the specified Value wasn't a Color? return null; } }
Factory class for computed CSS AnimatableStringValues.
/** * Factory class for computed CSS {@link AnimatableStringValue}s. */
protected class AnimatableStringValueFactory extends CSSValueFactory { protected AnimatableValue createAnimatableValue(AnimationTarget target, String pn, Value v) { return new AnimatableStringValue(target, v.getCssText()); } } }