You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-commits@xmlgraphics.apache.org by ca...@apache.org on 2006/08/14 00:37:05 UTC

svn commit: r431260 - in /xmlgraphics/batik/trunk/sources/org/apache/batik: anim/ anim/timing/ bridge/ util/

Author: cam
Date: Sun Aug 13 15:37:04 2006
New Revision: 431260

URL: http://svn.apache.org/viewvc?rev=431260&view=rev
Log:
1. The animation engine now pauses when there are no animations that need
   updating.

Modified:
    xmlgraphics/batik/trunk/sources/org/apache/batik/anim/AnimationEngine.java
    xmlgraphics/batik/trunk/sources/org/apache/batik/anim/timing/TimeContainer.java
    xmlgraphics/batik/trunk/sources/org/apache/batik/anim/timing/TimedDocumentRoot.java
    xmlgraphics/batik/trunk/sources/org/apache/batik/anim/timing/TimedElement.java
    xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGAnimationElementBridge.java
    xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGAnimationEngine.java
    xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGSetElementBridge.java
    xmlgraphics/batik/trunk/sources/org/apache/batik/util/RunnableQueue.java

Modified: xmlgraphics/batik/trunk/sources/org/apache/batik/anim/AnimationEngine.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/apache/batik/anim/AnimationEngine.java?rev=431260&r1=431259&r2=431260&view=diff
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/anim/AnimationEngine.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/anim/AnimationEngine.java Sun Aug 13 15:37:04 2006
@@ -122,7 +122,7 @@
     /**
      * Sets the current document time.
      */
-    public void setCurrentTime(float t) {
+    public float setCurrentTime(float t) {
         boolean p = pauseTime != 0;
         unpause();
         Calendar begin = timedDocumentRoot.getDocumentBeginTime();
@@ -132,7 +132,7 @@
         if (p) {
             pause();
         }
-        tick(t, true);
+        return tick(t, true);
     }
 
     /**
@@ -260,8 +260,8 @@
      * @param hyperlinking whether the document should be seeked to the given
      *                     time, as with hyperlinking
      */
-    protected void tick(float time, boolean hyperlinking) {
-        timedDocumentRoot.seekTo(time, hyperlinking);
+    protected float tick(float time, boolean hyperlinking) {
+        float waitTime = timedDocumentRoot.seekTo(time, hyperlinking);
         Iterator i = targets.entrySet().iterator();
         while (i.hasNext()) {
             Map.Entry e = (Map.Entry) i.next();
@@ -339,6 +339,7 @@
                 }
             }
         }
+        return waitTime;
     }
 
     /**

Modified: xmlgraphics/batik/trunk/sources/org/apache/batik/anim/timing/TimeContainer.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/apache/batik/anim/timing/TimeContainer.java?rev=431260&r1=431259&r2=431260&view=diff
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/anim/timing/TimeContainer.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/anim/timing/TimeContainer.java Sun Aug 13 15:37:04 2006
@@ -76,22 +76,39 @@
     }
 
     /**
-     * Calculates the local simple time.
+     * Calculates the local simple time.  Currently the hyperlinking parameter
+     * is ignored, so DOM timing events are fired during hyperlinking seeks.
+     * If we were following SMIL 2.1 rather than SMIL Animation, then these
+     * events would have to be surpressed.
+     *
+     * @return the number of seconds until this element becomes active again
+     *         if it currently is not, {@link Float.POSITIVE_INFINITY} if this
+     *         element will become active at some undetermined point in the
+     *         future (because of unresolved begin times, for example) or
+     *         will never become active again, or <code>0f</code> if the
+     *         element is currently active.
      */
-    protected void sampleAt(float parentSimpleTime, boolean hyperlinking) {
+    protected float sampleAt(float parentSimpleTime, boolean hyperlinking) {
         super.sampleAt(parentSimpleTime, hyperlinking);
-        sampleChildren(parentSimpleTime, hyperlinking);
+        // Maybe check the return value of the previous statement.
+        return sampleChildren(parentSimpleTime, hyperlinking);
     }
 
     /**
      * Samples all the child timed elements.
      */
-    protected void sampleChildren(float parentSimpleTime, boolean hyperlinking) {
+    protected float sampleChildren(float parentSimpleTime,
+                                   boolean hyperlinking) {
+        float mint = Float.POSITIVE_INFINITY;
         Iterator i = children.iterator();
         while (i.hasNext()) {
             TimedElement e = (TimedElement) i.next();
-            e.sampleAt(parentSimpleTime, hyperlinking);
+            float t = e.sampleAt(parentSimpleTime, hyperlinking);
+            if (t < mint) {
+                mint = t;
+            }
         }
+        return mint;
     }
 
     /**
@@ -104,6 +121,14 @@
             TimedElement e = (TimedElement) i.next();
             e.reset(clearCurrentBegin);
         }
+    }
+
+    /**
+     * Returns whether this timed element is for a constant animation (i.e., a
+     * 'set' animation.
+     */
+    protected boolean isConstantAnimation() {
+        return false;
     }
 
     /**

Modified: xmlgraphics/batik/trunk/sources/org/apache/batik/anim/timing/TimedDocumentRoot.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/apache/batik/anim/timing/TimedDocumentRoot.java?rev=431260&r1=431259&r2=431260&view=diff
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/anim/timing/TimedDocumentRoot.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/anim/timing/TimedDocumentRoot.java Sun Aug 13 15:37:04 2006
@@ -103,16 +103,19 @@
     /**
      * Samples the entire timegraph at the given time.
      */
-    public void seekTo(float time, boolean hyperlinking) {
+    public float seekTo(float time, boolean hyperlinking) {
         lastSampleTime = time;
         // Trace.enter(this, "seekTo", new Object[] { new Float(time) } ); try {
         propagationFlags.clear();
         // No time containers in SVG, so we don't have to worry
         // about a partial ordering of timed elements to sample.
+        float mint = Float.POSITIVE_INFINITY;
         TimedElement[] es = getChildren();
         for (int i = 0; i < es.length; i++) {
-            // System.err.print("[" + ((Test.AnimateElement) es[i]).id + "] ");
-            es[i].sampleAt(time, hyperlinking);
+            float t = es[i].sampleAt(time, hyperlinking);
+            if (t < mint) {
+                mint = t;
+            }
         }
         boolean needsUpdates;
         do {
@@ -121,10 +124,14 @@
                 if (es[i].shouldUpdateCurrentInterval) {
                     needsUpdates = true;
                     // System.err.print("{" + ((Test.AnimateElement) es[i]).id + "} ");
-                    es[i].sampleAt(time, hyperlinking);
+                    float t = es[i].sampleAt(time, hyperlinking);
+                    if (t < mint) {
+                        mint = t;
+                    }
                 }
             }
         } while (needsUpdates);
+        return mint;
         // } finally { Trace.exit(); }
     }
 
@@ -219,6 +226,15 @@
         }
         propagationFlags.add(it, ts);
         return true;
+    }
+
+    /**
+     * Invoked by timed elements in this document to indicate that the current
+     * interval will be re-evaluated at the next sample.  This should be
+     * overridden in a concrete class so that ticks can be scheduled immediately
+     * if they are currently paused due to no animations being active.
+     */
+    protected void currentIntervalWillUpdate() {
     }
 
     /**

Modified: xmlgraphics/batik/trunk/sources/org/apache/batik/anim/timing/TimedElement.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/apache/batik/anim/timing/TimedElement.java?rev=431260&r1=431259&r2=431260&view=diff
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/anim/timing/TimedElement.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/anim/timing/TimedElement.java Sun Aug 13 15:37:04 2006
@@ -536,8 +536,15 @@
      * is ignored, so DOM timing events are fired during hyperlinking seeks.
      * If we were following SMIL 2.1 rather than SMIL Animation, then these
      * events would have to be surpressed.
+     *
+     * @return the number of seconds until this element becomes active again
+     *         if it currently is not, {@link Float.POSITIVE_INFINITY} if this
+     *         element will become active at some undetermined point in the
+     *         future (because of unresolved begin times, for example) or
+     *         will never become active again, or <code>0f</code> if the
+     *         element is currently active.
      */
-    protected void sampleAt(float parentSimpleTime, boolean hyperlinking) {
+    protected float sampleAt(float parentSimpleTime, boolean hyperlinking) {
         // Trace.enter(this, "sampleAt", new Object[] { new Float(parentSimpleTime) } ); try {
         float time = parentSimpleTime; // No time containers in SVG.
 
@@ -600,8 +607,7 @@
         // begin and end times, or end the current interval and compute
         // a new one.
         boolean hasEnded = currentInterval != null
-            && (time < currentInterval.getBegin()
-                    || time >= currentInterval.getEnd());
+            && time > currentInterval.getEnd();
         // Fire any repeat events that should have been fired since the
         // last sample.
         if (currentInterval != null) {
@@ -723,6 +729,14 @@
         }
 
         lastSampleTime = time;
+        if (currentInterval != null) {
+            float t = currentInterval.getBegin() - time;
+            if (t > 0) {
+                return t;
+            }
+            return isConstantAnimation() ? currentInterval.getEnd() - time : 0;
+        }
+        return Float.POSITIVE_INFINITY;
         // } finally { Trace.exit(); }
     }
 
@@ -1240,6 +1254,7 @@
             handledEvents.put(e, ts);
         }
         ts.add(t);
+        root.currentIntervalWillUpdate();
     }
 
     /**
@@ -1322,6 +1337,12 @@
      * in document order.
      */
     public abstract boolean isBefore(TimedElement other);
+
+    /**
+     * Returns whether this timed element is for a constant animation (i.e., a
+     * 'set' animation.
+     */
+    protected abstract boolean isConstantAnimation();
 
     /**
      * Creates and returns a new {@link AnimationException}.

Modified: xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGAnimationElementBridge.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGAnimationElementBridge.java?rev=431260&r1=431259&r2=431260&view=diff
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGAnimationElementBridge.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGAnimationElementBridge.java Sun Aug 13 15:37:04 2006
@@ -494,6 +494,13 @@
     }
 
     /**
+     * Returns whether this is a constant animation (i.e., a 'set' animation).
+     */
+    protected boolean isConstantAnimation() {
+        return false;
+    }
+
+    /**
      * A TimedElement class for SVG animation elements.
      */
     protected class SVGTimedElement extends TimedElement {
@@ -616,6 +623,14 @@
                 }
             }
             return super.toString();
+        }
+
+        /**
+         * Returns whether this timed element is for a constant animation (i.e.,
+         * a 'set' animation.
+         */
+        protected boolean isConstantAnimation() {
+            return SVGAnimationElementBridge.this.isConstantAnimation();
         }
     }
 }

Modified: xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGAnimationEngine.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGAnimationEngine.java?rev=431260&r1=431259&r2=431260&view=diff
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGAnimationEngine.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGAnimationEngine.java Sun Aug 13 15:37:04 2006
@@ -367,6 +367,28 @@
     }
 
     /**
+     * Returns the current document time.
+     */
+    public float getCurrentTime() {
+        boolean p = pauseTime != 0;
+        unpause();
+        float t = timedDocumentRoot.getCurrentTime();
+        if (p) {
+            pause();
+        }
+        return t;
+    }
+
+    /**
+     * Sets the current document time.
+     */
+    public float setCurrentTime(float t) {
+        float ret = super.setCurrentTime(t);
+        animationTickRunnable.resume();
+        return ret;
+    }
+
+    /**
      * Creates a new returns a new TimedDocumentRoot object for the document.
      */
     protected TimedDocumentRoot createDocumentRoot() {
@@ -534,6 +556,16 @@
         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.
+         */
+        protected void currentIntervalWillUpdate() {
+            if (animationTickRunnable != null) {
+                animationTickRunnable.resume();
+            }
+        }
     }
 
     /**
@@ -569,9 +601,10 @@
                     tick(0, false);
                     // animationThread = new AnimationThread();
                     // animationThread.start();
-                    animationTickRunnable = new AnimationTickRunnable();
-                    ctx.getUpdateManager().getUpdateRunnableQueue().setIdleRunnable
-                        (animationTickRunnable);
+                    RunnableQueue q =
+                        ctx.getUpdateManager().getUpdateRunnableQueue();
+                    animationTickRunnable = new AnimationTickRunnable(q);
+                    q.setIdleRunnable(animationTickRunnable);
                 } catch (AnimationException ex) {
                     throw new BridgeException(ctx, ex.getElement().getElement(),
                                               ex.getMessage());
@@ -589,22 +622,44 @@
     /**
      * Idle runnable to tick the animation.
      */
-    protected class AnimationTickRunnable implements Runnable {
+    protected class AnimationTickRunnable
+            implements RunnableQueue.IdleRunnable {
+
         protected Calendar time = Calendar.getInstance();
         double second = -1.;
         int idx = -1;
         int frames;
+        long waitTime;
+        RunnableQueue q;
+        public AnimationTickRunnable(RunnableQueue q) {
+            this.q = q;
+        }
+        public void resume() {
+            Object lock = q.getIteratorLock();
+            synchronized (lock) {
+                lock.notify();
+            }
+        }
+        public long getWaitTime() {
+            return waitTime;
+        }
         public void run() {
             try {
                 try {
-                    time.setTimeInMillis(System.currentTimeMillis());
+                    long now = System.currentTimeMillis();
+                    time.setTimeInMillis(now);
                     float t = timedDocumentRoot.convertWallclockTime(time);
                     if (Math.floor(t) > second) {
                         second = Math.floor(t);
                         // System.err.println("fps: " + frames);
                         frames = 0;
                     }
-                    tick(t, false);
+                    float t2 = tick(t, false);
+                    if (t2 == Float.POSITIVE_INFINITY) {
+                        waitTime = Long.MAX_VALUE;
+                    } else {
+                        waitTime = now + (long) (t2 * 1000) - 2000;;
+                    }
                     frames++;
                 } catch (AnimationException ex) {
                     throw new BridgeException(ctx, ex.getElement().getElement(),

Modified: xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGSetElementBridge.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGSetElementBridge.java?rev=431260&r1=431259&r2=431260&view=diff
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGSetElementBridge.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGSetElementBridge.java Sun Aug 13 15:37:04 2006
@@ -60,4 +60,11 @@
     protected boolean canAnimateType(int type) {
         return true;
     }
+
+    /**
+     * Returns whether this is a constant animation (i.e., a 'set' animation).
+     */
+    protected boolean isConstantAnimation() {
+        return true;
+    }
 }

Modified: xmlgraphics/batik/trunk/sources/org/apache/batik/util/RunnableQueue.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/apache/batik/util/RunnableQueue.java?rev=431260&r1=431259&r2=431260&view=diff
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/util/RunnableQueue.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/util/RunnableQueue.java Sun Aug 13 15:37:04 2006
@@ -105,9 +105,14 @@
     protected volatile HaltingThread runnableQueueThread;
 
     /**
-     * The Runnable to run if the queue is empty.
+     * The {@link IdleRunnable} to run if the queue is empty.
      */
-    protected Runnable idleRunnable;
+    protected IdleRunnable idleRunnable;
+
+    /**
+     * The time (in milliseconds) that the idle runnable should be run next.
+     */
+    protected long idleRunnableWaitTime;
 
     /**
      * Creates a new RunnableQueue started in a new thread.
@@ -190,6 +195,7 @@
                 //     Thread.sleep(1);
                 // } catch (InterruptedException ie) { }
 
+                boolean usedIdleRunnable = false;
                 synchronized (list) {
                     if (state == SUSPENDING)
                         continue;
@@ -198,15 +204,25 @@
                     if (l == null) {
                         // No item to run, see if there is an idle runnable
                         // to run instead.
-                        if (idleRunnable != null) {
+                        if (idleRunnable != null && idleRunnableWaitTime
+                                < System.currentTimeMillis()) {
                             rable = idleRunnable;
+                            usedIdleRunnable = true;
                         } else {
                             // Wait for a runnable.
                             try {
-                                list.wait();
+                                if (idleRunnable != null && idleRunnableWaitTime
+                                        != Long.MAX_VALUE) {
+                                    long t = idleRunnableWaitTime
+                                        - System.currentTimeMillis();
+                                    list.wait(t);
+                                } else {
+                                    list.wait();
+                                }
                             } catch (InterruptedException ie) {
                                 // just loop again.
                             }
+                            idleRunnableWaitTime = 0;
                             continue; // start loop over again...
                         }
                     } else {
@@ -232,6 +248,10 @@
                     l.unlock();
                 }
                 runnableInvoked(rable);
+
+                if (usedIdleRunnable) {
+                    idleRunnableWaitTime = idleRunnable.getWaitTime();
+                }
             }
         } finally {
             synchronized (this) {
@@ -475,9 +495,10 @@
     /**
      * Sets a Runnable to be run whenever the queue is empty.
      */
-    public synchronized void setIdleRunnable(Runnable r) {
+    public synchronized void setIdleRunnable(IdleRunnable r) {
         synchronized (list) {
             idleRunnable = r;
+            idleRunnableWaitTime = 0;
             list.notify();
         }
     }
@@ -524,6 +545,23 @@
         if (runHandler != null) {
             runHandler.runnableInvoked(this, rable);
         }
+    }
+
+    /**
+     * A {@link Runnable} that can also inform the caller how long it should
+     * be until it is run again.
+     */
+    public interface IdleRunnable extends Runnable {
+
+        /**
+         * 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
+         */
+        long getWaitTime();
     }
 
     /**