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 2007/02/02 05:57:56 UTC

svn commit: r502489 - in /xmlgraphics/batik/trunk: resources/org/apache/batik/apps/svgbrowser/resources/ sources/org/apache/batik/anim/ sources/org/apache/batik/bridge/ sources/org/apache/batik/bridge/svg12/ test-sources/org/apache/batik/swing/ test-so...

Author: cam
Date: Thu Feb  1 20:57:56 2007
New Revision: 502489

URL: http://svn.apache.org/viewvc?view=rev&rev=502489
Log:
1. Ensure the animation engine of an SVG 1.2 resource document does not
   prevent the document from being GCed.
2. Fixed typo in Squiggle's Prefrences window.

Modified:
    xmlgraphics/batik/trunk/resources/org/apache/batik/apps/svgbrowser/resources/GUI.properties
    xmlgraphics/batik/trunk/sources/org/apache/batik/anim/AnimationEngine.java
    xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/BridgeContext.java
    xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGAnimationEngine.java
    xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/svg12/SVG12BridgeContext.java
    xmlgraphics/batik/trunk/test-sources/org/apache/batik/swing/JSVGMemoryLeakTest.java
    xmlgraphics/batik/trunk/test-sources/org/apache/batik/test/MemoryLeakTest.java

Modified: xmlgraphics/batik/trunk/resources/org/apache/batik/apps/svgbrowser/resources/GUI.properties
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/resources/org/apache/batik/apps/svgbrowser/resources/GUI.properties?view=diff&rev=502489&r1=502488&r2=502489
==============================================================================
--- xmlgraphics/batik/trunk/resources/org/apache/batik/apps/svgbrowser/resources/GUI.properties (original)
+++ xmlgraphics/batik/trunk/resources/org/apache/batik/apps/svgbrowser/resources/GUI.properties Thu Feb  1 20:57:56 2007
@@ -496,7 +496,7 @@
 PreferenceDialog.label.selection.xor.mode = Display selection overlay using XOR mode
 PreferenceDialog.label.animation.limit.cpu = Limit to percentage of CPU usage
 PreferenceDialog.label.percent = %
-PreferenceDialog.label.animation.limit.fps = Limit to number of frmaes per second
+PreferenceDialog.label.animation.limit.fps = Limit to number of frames per second
 PreferenceDialog.label.fps = fps
 PreferenceDialog.label.animation.limit.unlimited = Unlimited
 PreferenceDialog.label.show.debug.trace = Print debugging information to console

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?view=diff&rev=502489&r1=502488&r2=502489
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/anim/AnimationEngine.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/anim/AnimationEngine.java Thu Feb  1 20:57:56 2007
@@ -86,6 +86,43 @@
     }
 
     /**
+     * Disposes this animation engine.
+     */
+    public void dispose() {
+        // Remove any target listeners that are registered.
+        Iterator i = targets.entrySet().iterator();
+        while (i.hasNext()) {
+            Map.Entry e = (Map.Entry) i.next();
+            AnimationTarget target = (AnimationTarget) e.getKey();
+            TargetInfo info = (TargetInfo) e.getValue();
+
+            Iterator j = info.xmlAnimations.iterator();
+            while (j.hasNext()) {
+                DoublyIndexedTable.Entry e2 =
+                    (DoublyIndexedTable.Entry) j.next();
+                String namespaceURI = (String) e2.getKey1();
+                String localName = (String) e2.getKey2();
+                Sandwich sandwich = (Sandwich) e2.getValue();
+                if (sandwich.listenerRegistered) {
+                    target.removeTargetListener(namespaceURI, localName, false,
+                                                targetListener);
+                }
+            }
+
+            j = info.cssAnimations.entrySet().iterator();
+            while (j.hasNext()) {
+                Map.Entry e2 = (Map.Entry) j.next();
+                String propertyName = (String) e2.getKey();
+                Sandwich sandwich = (Sandwich) e2.getValue();
+                if (sandwich.listenerRegistered) {
+                    target.removeTargetListener(null, propertyName, true,
+                                                targetListener);
+                }
+            }
+        }
+    }
+
+    /**
      * Pauses the animations.
      */
     public void pause() {

Modified: xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/BridgeContext.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/BridgeContext.java?view=diff&rev=502489&r1=502488&r2=502489
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/BridgeContext.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/BridgeContext.java Thu Feb  1 20:57:56 2007
@@ -318,6 +318,15 @@
     }
 
     /**
+     * Calls dispose on this BridgeContext, if it is a child context.
+     */
+    protected void finalize() {
+        if (primaryContext != null) {
+            dispose();
+        }
+    }
+
+    /**
      * This function creates a new 'sub' BridgeContext to associated
      * with 'newDoc' if one currently doesn't exist, otherwise it
      * returns the BridgeContext currently associated with the
@@ -325,11 +334,14 @@
      * @param newDoc The document to get/create a BridgeContext for.
      */
     public BridgeContext createSubBridgeContext(SVGOMDocument newDoc) {
+        BridgeContext subCtx;
+
         CSSEngine eng = newDoc.getCSSEngine();
-        if (eng != null)
-            return (BridgeContext)newDoc.getCSSEngine().getCSSContext();
+        if (eng != null) {
+            subCtx = (BridgeContext) newDoc.getCSSEngine().getCSSContext();
+            return subCtx;
+        }
 
-        BridgeContext subCtx;
         subCtx = createBridgeContext(newDoc);
         subCtx.primaryContext = primaryContext != null ? primaryContext : this;
         subCtx.primaryContext.childContexts.add(new WeakReference(subCtx));
@@ -1383,10 +1395,19 @@
     }
 
     /**
+     * Clears the list of child BridgeContexts and disposes them if there are
+     * no more references to them.
+     */
+    protected void clearChildContexts() {
+        childContexts.clear();
+    }
+
+    /**
      * Disposes this BridgeContext.
      */
     public void dispose() {
-        childContexts.clear();
+        clearChildContexts();
+
         synchronized (eventListenerSet) {
             // remove all listeners added by Bridges
             Iterator iter = eventListenerSet.iterator();
@@ -1412,6 +1433,12 @@
         if (document != null) {
             removeDOMListeners();
         }
+
+        if (animationEngine != null) {
+            animationEngine.dispose();
+            animationEngine = null;
+        }
+
         Iterator iter = interpreterMap.values().iterator();
         while (iter.hasNext()) {
             Interpreter interpreter = (Interpreter)iter.next();

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?view=diff&rev=502489&r1=502488&r2=502489
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGAnimationEngine.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/SVGAnimationEngine.java Thu Feb  1 20:57:56 2007
@@ -20,6 +20,7 @@
 
 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;
@@ -277,6 +278,10 @@
      * Disposes this animation engine.
      */
     public void dispose() {
+        synchronized (this) {
+            pause();
+            super.dispose();
+        }
     }
 
     /**
@@ -437,7 +442,7 @@
                 UpdateManager um = ctx.getUpdateManager();
                 if (um != null) {
                     RunnableQueue q = um.getUpdateRunnableQueue();
-                    animationTickRunnable = new AnimationTickRunnable(q);
+                    animationTickRunnable = new AnimationTickRunnable(q, this);
                     q.setIdleRunnable(animationTickRunnable);
                 }
             } catch (AnimationException ex) {
@@ -657,12 +662,12 @@
     /**
      * Idle runnable to tick the animation, that reads times from System.in.
      */
-    protected class DebugAnimationTickRunnable extends AnimationTickRunnable {
+    protected static class DebugAnimationTickRunnable extends AnimationTickRunnable {
 
         float t = 0f;
 
-        public DebugAnimationTickRunnable(RunnableQueue q) {
-            super(q);
+        public DebugAnimationTickRunnable(RunnableQueue q, SVGAnimationEngine eng) {
+            super(q, eng);
             waitTime = Long.MAX_VALUE;
             new Thread() {
                 public void run() {
@@ -700,18 +705,22 @@
         }
 
         public void run() {
-            try {
+            SVGAnimationEngine eng = getAnimationEngine();
+            synchronized (eng) {
                 try {
-                    tick(t, false);
-                } catch (AnimationException ex) {
-                    throw new BridgeException(ctx, ex.getElement().getElement(),
-                                              ex.getMessage());
-                }
-            } catch (BridgeException ex) {
-                if (ctx.getUserAgent() == null) {
-                    ex.printStackTrace();
-                } else {
-                    ctx.getUserAgent().displayError(ex);
+                    try {
+                        eng.tick(t, false);
+                    } catch (AnimationException ex) {
+                        throw new BridgeException
+                            (eng.ctx, ex.getElement().getElement(),
+                             ex.getMessage());
+                    }
+                } catch (BridgeException ex) {
+                    if (eng.ctx.getUserAgent() == null) {
+                        ex.printStackTrace();
+                    } else {
+                        eng.ctx.getUserAgent().displayError(ex);
+                    }
                 }
             }
         }
@@ -720,7 +729,7 @@
     /**
      * Idle runnable to tick the animation.
      */
-    protected class AnimationTickRunnable
+    protected static class AnimationTickRunnable
             implements RunnableQueue.IdleRunnable {
 
         /**
@@ -773,12 +782,20 @@
         protected int timeIndex;
 
         /**
+         * A weak reference to the SVGAnimationEngine this AnimationTickRunnable
+         * is for.  We makes this a WeakReference so that a ticking animation
+         * engine does not prevent from being GCed.
+         */
+        protected WeakReference engRef;
+
+        /**
          * Creates a new AnimationTickRunnable.
          */
-        public AnimationTickRunnable(RunnableQueue q) {
+        public AnimationTickRunnable(RunnableQueue q, SVGAnimationEngine eng) {
             this.q = q;
+            this.engRef = new WeakReference(eng);
             // Initialize the past times to 100ms.
-            Arrays.fill( times, 100 );
+            Arrays.fill(times, 100);
             sumTime = 100 * NUM_TIMES;
         }
 
@@ -810,70 +827,83 @@
          * Performs one tick of the animation.
          */
         public void run() {
-            try {
+            SVGAnimationEngine eng = getAnimationEngine();
+            synchronized (eng) {
+                int animationLimitingMode = eng.animationLimitingMode;
+                float animationLimitingAmount = eng.animationLimitingAmount;
                 try {
-                    long before = System.currentTimeMillis();
-                    time.setTime(new Date(before));
-                    float t = timedDocumentRoot.convertWallclockTime(time);
-//                     if (Math.floor(t) > second) {
-//                         second = Math.floor(t);
-//                         System.err.println("fps: " + frames);
-//                         frames = 0;
-//                     }
-                    float t2 = 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;
+                    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;
                         }
-                        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;
+                        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;
                             }
-                            long newWaitTime = after + (long) delay;
-                            if (newWaitTime > waitTime) {
-                                waitTime = newWaitTime;
+                            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());
+                    }
+                } catch (BridgeException ex) {
+                    if (eng.ctx.getUserAgent() == null) {
+                        ex.printStackTrace();
+                    } else {
+                        eng.ctx.getUserAgent().displayError(ex);
                     }
-//                     frames++;
-                } catch (AnimationException ex) {
-                    throw new BridgeException(ctx, ex.getElement().getElement(),
-                                              ex.getMessage());
-                }
-            } catch (BridgeException ex) {
-                if (ctx.getUserAgent() == null) {
-                    ex.printStackTrace();
-                } else {
-                    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) {
+                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.
+         */
+        protected SVGAnimationEngine getAnimationEngine() {
+            return (SVGAnimationEngine) engRef.get();
         }
     }
 

Modified: xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/svg12/SVG12BridgeContext.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/svg12/SVG12BridgeContext.java?view=diff&rev=502489&r1=502488&r2=502489
==============================================================================
--- xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/svg12/SVG12BridgeContext.java (original)
+++ xmlgraphics/batik/trunk/sources/org/apache/batik/bridge/svg12/SVG12BridgeContext.java Thu Feb  1 20:57:56 2007
@@ -132,8 +132,8 @@
      * Disposes this BridgeContext.
      */
     public void dispose() {
+        clearChildContexts();
 
-        childContexts.clear();
         synchronized (eventListenerSet) {
             // remove all listeners added by Bridges
             Iterator iter = eventListenerSet.iterator();
@@ -169,6 +169,12 @@
             removeDOMListeners();
             removeBindingListener();
         }
+
+        if (animationEngine != null) {
+            animationEngine.dispose();
+            animationEngine = null;
+        }
+
         Iterator iter = interpreterMap.values().iterator();
         while (iter.hasNext()) {
             Interpreter interpreter = (Interpreter)iter.next();

Modified: xmlgraphics/batik/trunk/test-sources/org/apache/batik/swing/JSVGMemoryLeakTest.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/test-sources/org/apache/batik/swing/JSVGMemoryLeakTest.java?view=diff&rev=502489&r1=502488&r2=502489
==============================================================================
--- xmlgraphics/batik/trunk/test-sources/org/apache/batik/swing/JSVGMemoryLeakTest.java (original)
+++ xmlgraphics/batik/trunk/test-sources/org/apache/batik/swing/JSVGMemoryLeakTest.java Thu Feb  1 20:57:56 2007
@@ -186,7 +186,6 @@
             if (subCtxs[i] != null) {
                 SVGOMDocument doc = (SVGOMDocument) subCtxs[i].getDocument();
                 registerObjectDesc(subCtxs[i], "BridgeContext_" + doc.getURL());
-                System.err.println("found subctx for " + doc.getURL());
             }
         }
     }

Modified: xmlgraphics/batik/trunk/test-sources/org/apache/batik/test/MemoryLeakTest.java
URL: http://svn.apache.org/viewvc/xmlgraphics/batik/trunk/test-sources/org/apache/batik/test/MemoryLeakTest.java?view=diff&rev=502489&r1=502488&r2=502489
==============================================================================
--- xmlgraphics/batik/trunk/test-sources/org/apache/batik/test/MemoryLeakTest.java (original)
+++ xmlgraphics/batik/trunk/test-sources/org/apache/batik/test/MemoryLeakTest.java Thu Feb  1 20:57:56 2007
@@ -147,8 +147,8 @@
         if (objStr.length() > 40)
             objStr = objStr.substring(0,40) + "..." ;
         System.err.println(">>>>> Objects not cleared: " + objStr);
-        // System.err.println("Waiting for heap dump...");
-        // try { Thread.sleep(60000); } catch (InterruptedException ie) { }
+        // System.err.println("Waiting 5 second for heap dump...");
+        // try { Thread.sleep(5000); } catch (InterruptedException ie) { }
         return false;
     }
 
@@ -223,8 +223,8 @@
         if (objStr.length() > 40)
             objStr = objStr.substring(0,40) + "..." ;
         System.err.println(">>>>> Objects not cleared: " + objStr);
-        // System.err.println("Waiting for heap dump...");
-        // try { Thread.sleep(60000); } catch (InterruptedException ie) { }
+        // System.err.println("Waiting for 5 seconds for heap dump...");
+        // try { Thread.sleep(5000); } catch (InterruptedException ie) { }
         return false;
     }