deweese 2003/07/07 17:16:58 Modified: . build.bat build.xml samples/tests/spec/scripting memoryLeak1.svg sources/org/apache/batik/bridge BaseScriptingEnvironment.java BridgeContext.java FocusManager.java sources/org/apache/batik/dom AbstractDocument.java sources/org/apache/batik/dom/svg SVGOMStyleElement.java sources/org/apache/batik/dom/util DocumentDescriptor.java sources/org/apache/batik/gvt AbstractGraphicsNode.java sources/org/apache/batik/script/rhino RhinoInterpreter.java sources/org/apache/batik/swing JSVGCanvas.java sources/org/apache/batik/swing/gvt JGVTComponent.java sources/org/apache/batik/swing/svg JSVGComponent.java sources/org/apache/batik/util RunnableQueue.java test-resources/org/apache/batik/swing unitTesting.xml test-resources/org/apache/batik/swing/resources TestMessages.properties test-resources/org/apache/batik/test/svg/resources Messages.properties test-sources/org/apache/batik/swing JSVGCanvasHandler.java JSVGMemoryLeakTest.java NullURITest.java test-sources/org/apache/batik/test MemoryLeakTest.java test-sources/org/apache/batik/test/svg JSVGRenderingAccuracyTest.java Added: test-references/test-resources/org/apache/batik/test/svg SetSVGDocumentTest.png test-sources/org/apache/batik/swing NullSetSVGDocumentTest.java SetSVGDocumentTest.java Log: 1) setSVGDocument with a Document that has been previously viewed in the Canvas now works (actually using setSVGDocument after viewing any dynamic document used to have problems). 2) setSVGDocument with a non-Batik Document (SVGOMDocument) now works. 3) setSVGDocument with 'null' now releases all heavy resources and makes the Canvas display only Background. 4) Fixed a Memory leak that prevent any DOM node created from a stream from going to GC (DocumentDescriptor kept a hard reference to Elements to track line numbers). 5) 'style' and 'script' elements no longer include the contents of XML Comments (unless using a CDATA block). 6) RunnableQueue now catches all exceptions. 7) Various affine actions are now public classes (Zoom, Pan, Rotate). 8) New MemoryLeak tests PR: 21125, 21352, 18640 Revision Changes Path 1.11 +2 -3 xml-batik/build.bat Index: build.bat =================================================================== RCS file: /home/cvs/xml-batik/build.bat,v retrieving revision 1.10 retrieving revision 1.11 diff -u -r1.10 -r1.11 --- build.bat 2 Jul 2003 08:18:07 -0000 1.10 +++ build.bat 8 Jul 2003 00:16:56 -0000 1.11 @@ -13,17 +13,16 @@ :gotJavaHome if not "%ANT_HOME%" == "" goto gotAntHome -set ANT_HOME=. :: ----- Set Up The Runtime Classpath ----------------------------------------- -set CP=%JAVA_HOME%\lib\tools.jar;%ANT_HOME%\lib\build\ant_1_4_1.jar;.\lib\build\crimson-ant.jar;.\lib\build\jaxp.jar +set CP=%JAVA_HOME%\lib\tools.jar;lib\build\ant_1_4_1.jar;.\lib\build\crimson-ant.jar;.\lib\build\jaxp.jar :: ----- Execute The Requested Build ------------------------------------------ -%JAVA_HOME%\bin\java.exe %ANT_OPTS% -classpath %CP% org.apache.tools.ant.Main -emacs -Dant.home=%ANT_HOME% %1 -Dargs="%2 %3 %4 %5 %6 %7 %8 %9" +%JAVA_HOME%\bin\java.exe %ANT_OPTS% -classpath %CP% org.apache.tools.ant.Main -emacs -Dant.home=. %1 -Dargs="%2 %3 %4 %5 %6 %7 %8 %9" :: ----- Cleanup the environment ---------------------------------------------- 1.132 +2 -1 xml-batik/build.xml Index: build.xml =================================================================== RCS file: /home/cvs/xml-batik/build.xml,v retrieving revision 1.131 retrieving revision 1.132 diff -u -r1.131 -r1.132 --- build.xml 5 Jul 2003 00:15:07 -0000 1.131 +++ build.xml 8 Jul 2003 00:16:56 -0000 1.132 @@ -1075,6 +1075,7 @@ <java fork="yes" classname="${class-prefix}.test.xml.XMLTestSuiteRunner"> <!-- <jvmarg value="-Xrunhprof:format=b" /> --> +<!-- <jvmarg value="-Xrunhprof:net=localhost:7001,format=b" /> --> <classpath> <pathelement location="${dest}" /> <path refid="libs-classpath"/> 1.2 +49 -15 xml-batik/samples/tests/spec/scripting/memoryLeak1.svg Index: memoryLeak1.svg =================================================================== RCS file: /home/cvs/xml-batik/samples/tests/spec/scripting/memoryLeak1.svg,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- memoryLeak1.svg 5 Jul 2003 00:15:07 -0000 1.1 +++ memoryLeak1.svg 8 Jul 2003 00:16:56 -0000 1.2 @@ -17,28 +17,62 @@ <!-- @version $Id$ --> <!-- ====================================================================== --> -<?xml-stylesheet type="text/css" href="../../resources/style/test.css" ?> - <svg id="body" width="450" height="500" viewBox="0 0 450 500"> - <title><text> children 'onload'</title> - - <text x="50%" y="45" class="title"><text> children in 'onload'</text> - <script type="text/ecmascript"><![CDATA[ var inRegard=false; + var elems = new Array + ("t1", "t2", "r1", "r2", "c1", "c2", "ts1", "ts2", "xxx"); + function regardStart() { - inRegard=true; - var elem = document.getElementById("t1"); - regardTestInstance.registerObjectDesc(elem, "T1"); - elem.parentNode.removeChild(elem); - regardTestInstance.scriptDone(); + inRegard=true; + + var elem; + for(var i=0; i<elems.length; i++) { + var elem = document.getElementById(elems[i]); + regardTestInstance.registerElement(elem, elems[i]); + elem.parentNode.removeChild(elem); + } + + setTimeout("checkElem()", 10); + } + + function checkElem() { + regardTestInstance.checkObjects(elems); + // setTimeout("regardTestInstance.scriptDone()", 30000); + regardTestInstance.scriptDone(); } ]]></script> + <defs> + <rect id="xxx" x="10" y="150" width="100" height="50" fill="purple"/> + </defs> + <g id="test-content"> - <g style="font-size:40" > - <text id="t1_bg" x="70" y="135" style="fill:gold">The good the bad</text> - <text id="t1" x="70" y="135" style="fill:crimson">The good the bad</text> + <g style="font-size:20" > + <text id="t1_bg" x="5" y="135" fill="purple" >Simple Text</text> + <text id="t2" x="155" y="135" fill="gold" >Simple Text</text> + <text id="t1" x="305" y="135" fill="crimson">Simple Text</text> + </g> + + <g> + <rect id="r_bg" x="10" y="150" width="100" height="50" fill="purple"/> + <rect id="r1" x="160" y="150" width="100" height="50" fill="crimson"/> + <rect id="r2" x="310" y="150" width="100" height="50" fill="gold"/> + </g> + + <g> + <circle id="c_bg" cx="60" cy="235" r="25" fill="purple"/> + <circle id="c1" cx="210" cy="235" r="25" fill="crimson"/> + <circle id="c2" cx="360" cy="235" r="25" fill="gold"/> + </g> + + <g style="font-size:15" > + <text x="5" y="290" fill="purple">Some + <tspan id="ts_bg" font-weight="bold">Complex</tspan> Text</text> + <text x="155" y="290" fill="crimson">Some + <tspan id="ts1" font-weight="bold">Complex</tspan> Text</text> + <text x="305" y="290" fill="gold">Some + <tspan id="ts2" font-weight="bold">Complex</tspan> Text</text> </g> </g> </svg> 1.22 +4 -2 xml-batik/sources/org/apache/batik/bridge/BaseScriptingEnvironment.java Index: BaseScriptingEnvironment.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/bridge/BaseScriptingEnvironment.java,v retrieving revision 1.21 retrieving revision 1.22 diff -u -r1.21 -r1.22 --- BaseScriptingEnvironment.java 3 Jul 2003 02:00:00 -0000 1.21 +++ BaseScriptingEnvironment.java 8 Jul 2003 00:16:56 -0000 1.22 @@ -365,7 +365,9 @@ if (n != null) { StringBuffer sb = new StringBuffer(); while (n != null) { - sb.append(n.getNodeValue()); + if (n.getNodeType() == n.CDATA_SECTION_NODE + || n.getNodeType() == n.TEXT_NODE) + sb.append(n.getNodeValue()); n = n.getNextSibling(); } reader = new StringReader(sb.toString()); 1.65 +2 -1 xml-batik/sources/org/apache/batik/bridge/BridgeContext.java Index: BridgeContext.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/bridge/BridgeContext.java,v retrieving revision 1.64 retrieving revision 1.65 diff -u -r1.64 -r1.65 --- BridgeContext.java 1 Jul 2003 09:34:17 -0000 1.64 +++ BridgeContext.java 8 Jul 2003 00:16:56 -0000 1.65 @@ -988,6 +988,7 @@ if (cssEngine != null) { cssEngine.removeCSSEngineListener(cssPropertiesChangedListener); cssEngine.dispose(); + svgDocument.setCSSEngine(null); } if (focusManager != null) { focusManager.dispose(); 1.5 +2 -1 xml-batik/sources/org/apache/batik/bridge/FocusManager.java Index: FocusManager.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/bridge/FocusManager.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- FocusManager.java 11 Apr 2003 13:54:43 -0000 1.4 +++ FocusManager.java 8 Jul 2003 00:16:57 -0000 1.5 @@ -96,6 +96,7 @@ * Removes all listeners attached to the document and that manage focus. */ public void dispose() { + if (document == null) return; EventTarget target = (EventTarget)document; target.removeEventListener("click", mouseclickListener, true); target.removeEventListener("mouseover", mouseoverListener, true); 1.18 +67 -62 xml-batik/sources/org/apache/batik/dom/AbstractDocument.java Index: AbstractDocument.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/dom/AbstractDocument.java,v retrieving revision 1.17 retrieving revision 1.18 diff -u -r1.17 -r1.18 --- AbstractDocument.java 11 Apr 2003 13:56:01 -0000 1.17 +++ AbstractDocument.java 8 Jul 2003 00:16:57 -0000 1.18 @@ -206,77 +206,82 @@ */ public Node importNode(Node importedNode, boolean deep) throws DOMException { + /* TED: This is bad because it usually does not create the + * the proper subclass of Element for the document it is + * being imported into based on namespace/tag name. + */ + /** if (importedNode instanceof AbstractNode) { AbstractNode an = (AbstractNode)importedNode; return (deep) ? an.deepExport(an.cloneNode(false), this) : an.export(an.cloneNode(false), this); - } else { - Node result; - switch (importedNode.getNodeType()) { - case ELEMENT_NODE: - Element e = createElementNS(importedNode.getNamespaceURI(), - importedNode.getNodeName()); - result = e; - if (importedNode.hasAttributes()) { - NamedNodeMap attr = importedNode.getAttributes(); - int len = attr.getLength(); - for (int i = 0; i < len; i++) { - Attr a = (Attr)attr.item(i); - if (a.getSpecified()) { - e.setAttributeNodeNS((Attr)importNode(a, true)); - } + } + */ + + Node result; + switch (importedNode.getNodeType()) { + case ELEMENT_NODE: + Element e = createElementNS(importedNode.getNamespaceURI(), + importedNode.getNodeName()); + result = e; + if (importedNode.hasAttributes()) { + NamedNodeMap attr = importedNode.getAttributes(); + int len = attr.getLength(); + for (int i = 0; i < len; i++) { + Attr a = (Attr)attr.item(i); + if (a.getSpecified()) { + e.setAttributeNodeNS((Attr)importNode(a, true)); } } - break; - - case ATTRIBUTE_NODE: - result = createAttributeNS(importedNode.getNamespaceURI(), - importedNode.getNodeName()); - break; - - case TEXT_NODE: - result = createTextNode(importedNode.getNodeValue()); - deep = false; - break; - - case CDATA_SECTION_NODE: - result = createCDATASection(importedNode.getNodeValue()); - deep = false; - break; - - case ENTITY_REFERENCE_NODE: - result = createEntityReference(importedNode.getNodeName()); - break; - - case PROCESSING_INSTRUCTION_NODE: - result = createProcessingInstruction - (importedNode.getNodeName(), - importedNode.getNodeValue()); - deep = false; - break; - - case COMMENT_NODE: - result = createComment(importedNode.getNodeValue()); - deep = false; - break; - - default: - throw createDOMException(DOMException.NOT_SUPPORTED_ERR, - "import.node", - new Object[] {}); } - - if (deep) { - for (Node n = importedNode.getFirstChild(); - n != null; - n = n.getNextSibling()) { - result.appendChild(importNode(n, true)); - } + break; + + case ATTRIBUTE_NODE: + result = createAttributeNS(importedNode.getNamespaceURI(), + importedNode.getNodeName()); + break; + + case TEXT_NODE: + result = createTextNode(importedNode.getNodeValue()); + deep = false; + break; + + case CDATA_SECTION_NODE: + result = createCDATASection(importedNode.getNodeValue()); + deep = false; + break; + + case ENTITY_REFERENCE_NODE: + result = createEntityReference(importedNode.getNodeName()); + break; + + case PROCESSING_INSTRUCTION_NODE: + result = createProcessingInstruction + (importedNode.getNodeName(), + importedNode.getNodeValue()); + deep = false; + break; + + case COMMENT_NODE: + result = createComment(importedNode.getNodeValue()); + deep = false; + break; + + default: + throw createDOMException(DOMException.NOT_SUPPORTED_ERR, + "import.node", + new Object[] {}); + } + + if (deep) { + for (Node n = importedNode.getFirstChild(); + n != null; + n = n.getNextSibling()) { + result.appendChild(importNode(n, true)); } - - return result; } + return result; } /** 1.14 +4 -2 xml-batik/sources/org/apache/batik/dom/svg/SVGOMStyleElement.java Index: SVGOMStyleElement.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/dom/svg/SVGOMStyleElement.java,v retrieving revision 1.13 retrieving revision 1.14 diff -u -r1.13 -r1.14 --- SVGOMStyleElement.java 11 Apr 2003 13:56:16 -0000 1.13 +++ SVGOMStyleElement.java 8 Jul 2003 00:16:57 -0000 1.14 @@ -98,7 +98,9 @@ if (n != null) { StringBuffer sb = new StringBuffer(); while (n != null) { - sb.append(n.getNodeValue()); + if (n.getNodeType() == n.CDATA_SECTION_NODE + || n.getNodeType() == n.TEXT_NODE) + sb.append(n.getNodeValue()); n = n.getNextSibling(); } text = sb.toString(); 1.2 +67 -35 xml-batik/sources/org/apache/batik/dom/util/DocumentDescriptor.java Index: DocumentDescriptor.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/dom/util/DocumentDescriptor.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- DocumentDescriptor.java 13 Feb 2001 19:45:15 -0000 1.1 +++ DocumentDescriptor.java 8 Jul 2003 00:16:57 -0000 1.2 @@ -10,6 +10,8 @@ import org.w3c.dom.Element; +import org.apache.batik.util.CleanerThread; + /** * This class contains informations about a document. * @@ -44,7 +46,9 @@ * Returns the number of elements in the document. */ public int getNumberOfElements() { - return count; + synchronized (this) { + return count; + } } /** @@ -52,14 +56,18 @@ * @return zero if the information is unknown. */ public int getLocationLine(Element elt) { - int hash = elt.hashCode() & 0x7FFFFFFF; - int index = hash % table.length; - - for (Entry e = table[index]; e != null; e = e.next) { - if ((e.hash == hash) && e.element.equals(elt)) { - return e.locationLine; - } - } + synchronized (this) { + int hash = elt.hashCode() & 0x7FFFFFFF; + int index = hash % table.length; + + for (Entry e = table[index]; e != null; e = e.next) { + if (e.hash != hash) + continue; + Object o = e.get(); + if (o == elt) + return e.locationLine; + } + } return 0; } @@ -67,24 +75,28 @@ * Sets the location in the source file of the end element. */ public void setLocationLine(Element elt, int line) { - int hash = elt.hashCode() & 0x7FFFFFFF; - int index = hash % table.length; - - for (Entry e = table[index]; e != null; e = e.next) { - if ((e.hash == hash) && e.element.equals(elt)) { - e.locationLine = line; - } - } - - // The key is not in the hash table - int len = table.length; - if (count++ >= (len * 3) >>> 2) { - rehash(); - index = hash % table.length; - } - - Entry e = new Entry(hash, elt, line, table[index]); - table[index] = e; + synchronized (this) { + int hash = elt.hashCode() & 0x7FFFFFFF; + int index = hash % table.length; + + for (Entry e = table[index]; e != null; e = e.next) { + if (e.hash != hash) + continue; + Object o = e.get(); + if (o == elt) + e.locationLine = line; + } + + // The key is not in the hash table + int len = table.length; + if (count++ >= (len * 3) >>> 2) { + rehash(); + index = hash % table.length; + } + + Entry e = new Entry(hash, elt, line, table[index]); + table[index] = e; + } } /** @@ -107,21 +119,37 @@ } } + protected void removeEntry(Entry e) { + synchronized (this) { + int hash = e.hash; + int index = hash % table.length; + Entry curr = table[index]; + Entry prev = null; + while (curr != e) { + prev = curr; + curr = curr.next; + } + if (curr == null) return; // already remove??? + + if (prev == null) + // First entry. + table[index] = curr.next; + else + prev.next = curr.next; + count--; + } + } + /** * To manage collisions */ - protected static class Entry { + protected class Entry extends CleanerThread.WeakReferenceCleared { /** * The hash code */ public int hash; /** - * The element - */ - public Element element; - - /** * The line number. */ public int locationLine; @@ -135,10 +163,14 @@ * Creates a new entry */ public Entry(int hash, Element element, int locationLine, Entry next) { + super(element); this.hash = hash; - this.element = element; this.locationLine = locationLine; this.next = next; } + + public void cleared() { + removeEntry(this); + } } } 1.49 +2 -1 xml-batik/sources/org/apache/batik/gvt/AbstractGraphicsNode.java Index: AbstractGraphicsNode.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/gvt/AbstractGraphicsNode.java,v retrieving revision 1.48 retrieving revision 1.49 diff -u -r1.48 -r1.49 --- AbstractGraphicsNode.java 30 May 2003 01:07:15 -0000 1.48 +++ AbstractGraphicsNode.java 8 Jul 2003 00:16:57 -0000 1.49 @@ -602,6 +602,7 @@ (this, GraphicsNodeChangeEvent.CHANGE_STARTED); changeStartedEvent.setChangeSrc(changeSrc); fireGraphicsNodeChangeStarted(changeStartedEvent); + changeStartedEvent.setChangeSrc(null); } // 1.27 +3 -1 xml-batik/sources/org/apache/batik/script/rhino/RhinoInterpreter.java Index: RhinoInterpreter.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/script/rhino/RhinoInterpreter.java,v retrieving revision 1.26 retrieving revision 1.27 diff -u -r1.26 -r1.27 --- RhinoInterpreter.java 5 Jul 2003 00:15:07 -0000 1.26 +++ RhinoInterpreter.java 8 Jul 2003 00:16:57 -0000 1.27 @@ -174,6 +174,8 @@ if (!contexts.contains(ctx)) { ctx.setWrapFactory(wrapFactory); ctx.setSecurityController(securityController); + // This prevents a serious memory leak where + // all the SVG document state is preserved. ctx.setCachingEnabled(false); contexts.add(ctx); 1.40 +12 -12 xml-batik/sources/org/apache/batik/swing/JSVGCanvas.java Index: JSVGCanvas.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/swing/JSVGCanvas.java,v retrieving revision 1.39 retrieving revision 1.40 diff -u -r1.39 -r1.40 --- JSVGCanvas.java 17 Jun 2003 01:37:57 -0000 1.39 +++ JSVGCanvas.java 8 Jul 2003 00:16:57 -0000 1.40 @@ -503,7 +503,7 @@ /** * A swing action to reset the rendering transform of the canvas. */ - protected class ResetTransformAction extends AbstractAction { + public class ResetTransformAction extends AbstractAction { public void actionPerformed(ActionEvent evt) { fragmentIdentifier = null; resetRenderingTransform(); @@ -517,7 +517,7 @@ * 0,0 so scale and rotate occur around the middle of * the display. */ - protected class AffineAction extends AbstractAction { + public class AffineAction extends AbstractAction { AffineTransform at; public AffineAction(AffineTransform at) { this.at = at; @@ -545,7 +545,7 @@ * A swing action to apply a zoom factor to the canvas. * This can be used to zoom in (scale > 1) and out (scale <1). */ - protected class ZoomAction extends AffineAction { + public class ZoomAction extends AffineAction { public ZoomAction(double scale) { super(AffineTransform.getScaleInstance(scale, scale)); } @@ -557,21 +557,21 @@ /** * A swing action to zoom in the canvas. */ - protected class ZoomInAction extends ZoomAction { + public class ZoomInAction extends ZoomAction { ZoomInAction() { super(2); } } /** * A swing action to zoom out the canvas. */ - protected class ZoomOutAction extends ZoomAction { + public class ZoomOutAction extends ZoomAction { ZoomOutAction() { super(.5); } } /** * A swing action to Rotate the canvas. */ - protected class RotateAction extends AffineAction { + public class RotateAction extends AffineAction { public RotateAction(double theta) { super(AffineTransform.getRotateInstance(theta)); } @@ -580,7 +580,7 @@ /** * A swing action to Pan/scroll the canvas. */ - protected class ScrollAction extends AffineAction { + public class ScrollAction extends AffineAction { public ScrollAction(double tx, double ty) { super(AffineTransform.getTranslateInstance(tx, ty)); } @@ -590,7 +590,7 @@ * A swing action to scroll the canvas to the right, * by a fixed amount */ - protected class ScrollRightAction extends ScrollAction { + public class ScrollRightAction extends ScrollAction { public ScrollRightAction(int inc) { super(-inc, 0); } @@ -600,7 +600,7 @@ * A swing action to scroll the canvas to the left, * by a fixed amount */ - protected class ScrollLeftAction extends ScrollAction { + public class ScrollLeftAction extends ScrollAction { public ScrollLeftAction(int inc) { super(inc, 0); } @@ -610,7 +610,7 @@ * A swing action to scroll the canvas up, * by a fixed amount */ - protected class ScrollUpAction extends ScrollAction { + public class ScrollUpAction extends ScrollAction { public ScrollUpAction(int inc) { super(0, inc); } @@ -620,7 +620,7 @@ * A swing action to scroll the canvas down, * by a fixed amount */ - protected class ScrollDownAction extends ScrollAction { + public class ScrollDownAction extends ScrollAction { public ScrollDownAction(int inc) { super(0, -inc); } 1.34 +6 -1 xml-batik/sources/org/apache/batik/swing/gvt/JGVTComponent.java Index: JGVTComponent.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/swing/gvt/JGVTComponent.java,v retrieving revision 1.33 retrieving revision 1.34 diff -u -r1.33 -r1.34 --- JGVTComponent.java 11 Apr 2003 13:59:20 -0000 1.33 +++ JGVTComponent.java 8 Jul 2003 00:16:57 -0000 1.34 @@ -675,6 +675,7 @@ textSelectionManager = null; } renderer = null; + image = null; gvtRoot = null; } @@ -822,6 +823,10 @@ needRender = false; } else { immediateRepaint(); + } + + if (eventDispatcher != null) { + eventDispatcher.setRootNode(gvtRoot); } } 1.72 +94 -13 xml-batik/sources/org/apache/batik/swing/svg/JSVGComponent.java Index: JSVGComponent.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/swing/svg/JSVGComponent.java,v retrieving revision 1.71 retrieving revision 1.72 diff -u -r1.71 -r1.72 --- JSVGComponent.java 19 Jun 2003 00:32:11 -0000 1.71 +++ JSVGComponent.java 8 Jul 2003 00:16:57 -0000 1.72 @@ -49,6 +49,7 @@ import org.apache.batik.bridge.UserAgent; import org.apache.batik.bridge.ViewBox; import org.apache.batik.dom.svg.SVGDOMImplementation; +import org.apache.batik.dom.util.DOMUtilities; import org.apache.batik.dom.util.XLinkSupport; import org.apache.batik.ext.awt.image.spi.ImageTagRegistry; import org.apache.batik.gvt.CanvasGraphicsNode; @@ -63,6 +64,8 @@ import org.apache.batik.util.RunnableQueue; import org.apache.batik.util.SVGConstants; import org.apache.batik.util.XMLResourceDescriptor; +import org.w3c.dom.Document; +import org.w3c.dom.DOMImplementation; import org.w3c.dom.Element; import org.w3c.dom.svg.SVGAElement; import org.w3c.dom.svg.SVGDocument; @@ -463,14 +466,99 @@ } /** - * Sets the SVG document to display. + * Sets the Document to display. If the document does not use + * Batik's SVG DOM Implemenation it will be cloned into that + * implementation. In this case you should use 'getSVGDocument()' + * to get the actual DOM that is attached to the rendering interface. + */ + public void setDocument(Document doc) { + if ((doc != null) && + !(doc.getImplementation() instanceof SVGDOMImplementation)) { + DOMImplementation impl; + impl = SVGDOMImplementation.getDOMImplementation(); + Document d = DOMUtilities.deepCloneDocument(doc, impl); + doc = d; + } + setSVGDocument((SVGDocument)doc); + } + + /** + * Sets the SVGDocument to display. If the document does not use + * Batik's SVG DOM Implemenation it will be cloned into that + * implementation. In this case you should use 'getSVGDocument()' + * to get the actual DOM that is attached to the rendering + * interface. */ public void setSVGDocument(SVGDocument doc) { stopProcessing(); - if (!(doc.getImplementation() instanceof SVGDOMImplementation)) { - throw new IllegalArgumentException("Invalid DOM implementation."); + + if ((doc != null) && + !(doc.getImplementation() instanceof SVGDOMImplementation)) { + DOMImplementation impl; + impl = SVGDOMImplementation.getDOMImplementation(); + Document d = DOMUtilities.deepCloneDocument(doc, impl); + doc = (SVGDocument)d; + } + + if (updateManager == null) { + // No update manager just install new document. + installSVGDocument(doc); + } else { + // We have to wait for the update manager to stop + // before we install the new document otherwise bad + // things can happen with the update manager. + final SVGDocument svgdoc = doc; + updateManager.addUpdateManagerListener + (new UpdateManagerListener () { + UpdateManager um = updateManager; + public void managerStopped(UpdateManagerEvent e) { + // Remove ourselves from the old update manger, + // and install the new document. + um.removeUpdateManagerListener(this); + EventQueue.invokeLater(new Runnable() { + public void run() { + installSVGDocument(svgdoc); + } + }); + } + // There really should be an updateManagerAdapter. + public void managerStarted(UpdateManagerEvent e) { } + public void managerSuspended(UpdateManagerEvent e) { } + public void managerResumed(UpdateManagerEvent e) { } + public void updateStarted(UpdateManagerEvent e) { } + public void updateCompleted(UpdateManagerEvent e) { } + public void updateFailed(UpdateManagerEvent e) { } + }); + } + + } + + /** + * This does the real work of installing the SVG Document after + * the update manager from the previous document (if any) has been + * properly 'shut down'. + */ + protected void installSVGDocument(SVGDocument doc) { + svgDocument = doc; + + if (bridgeContext != null) { + bridgeContext.dispose(); + bridgeContext = null; } + releaseRenderingReferences(); + + if (doc == null) { + isDynamicDocument = false; + isInteractiveDocument = false; + disableInteractions = true; + initialTransform = new AffineTransform(); + setRenderingTransform(initialTransform, false); + Dimension d = getSize(); + repaint(0, 0, d.width, d.height); + return; + } + switch (documentState) { case ALWAYS_STATIC: isDynamicDocument = false; @@ -489,21 +577,15 @@ if (isDynamicDocument) isInteractiveDocument = true; else - isInteractiveDocument = BridgeContext.isInteractiveDocument(doc); + isInteractiveDocument = + BridgeContext.isInteractiveDocument(doc); } - // System.err.println("Dynamic: " + isDynamicDocument); - // System.err.println("Interactive: " + isInteractiveDocument); - - svgDocument = doc; Element root = doc.getDocumentElement(); String znp = root.getAttributeNS (null, SVGConstants.SVG_ZOOM_AND_PAN_ATTRIBUTE); disableInteractions = !znp.equals(SVGConstants.SVG_MAGNIFY_VALUE); - if (bridgeContext != null) { - bridgeContext.dispose(); - } bridgeContext = createBridgeContext(); nextGVTTreeBuilder = new GVTTreeBuilder(doc, bridgeContext); nextGVTTreeBuilder.setPriority(Thread.MIN_PRIORITY); @@ -514,7 +596,6 @@ ((GVTTreeBuilderListener)it.next()); } - releaseRenderingReferences(); initializeEventHandling(); if (gvtTreeBuilder == null && 1.12 +8 -2 xml-batik/sources/org/apache/batik/util/RunnableQueue.java Index: RunnableQueue.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/util/RunnableQueue.java,v retrieving revision 1.11 retrieving revision 1.12 diff -u -r1.11 -r1.12 --- RunnableQueue.java 11 Apr 2003 13:59:29 -0000 1.11 +++ RunnableQueue.java 8 Jul 2003 00:16:57 -0000 1.12 @@ -158,7 +158,13 @@ rable = l.runnable; } - rable.run(); + try { + rable.run(); + } catch (Throwable t) { + // Might be nice to notify someone directly. + // But this is more or less what Swing does. + t.printStackTrace(); + } l.unlock(); runnableInvoked(rable); } 1.1 xml-batik/test-references/test-resources/org/apache/batik/test/svg/SetSVGDocumentTest.png <<Binary file>> 1.4 +7 -1 xml-batik/test-resources/org/apache/batik/swing/unitTesting.xml Index: unitTesting.xml =================================================================== RCS file: /home/cvs/xml-batik/test-resources/org/apache/batik/swing/unitTesting.xml,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- unitTesting.xml 5 Jul 2003 00:15:08 -0000 1.3 +++ unitTesting.xml 8 Jul 2003 00:16:58 -0000 1.4 @@ -20,4 +20,10 @@ <test id="NullURITest" class="org.apache.batik.swing.NullURITest" /> + + <test id="SetSVGDocumentTest" + class="org.apache.batik.swing.SetSVGDocumentTest" /> + + <test id="NullSetSVGDocumentTest" + class="org.apache.batik.swing.NullSetSVGDocumentTest" /> </testSuite> 1.2 +8 -3 xml-batik/test-resources/org/apache/batik/swing/resources/TestMessages.properties Index: TestMessages.properties =================================================================== RCS file: /home/cvs/xml-batik/test-resources/org/apache/batik/swing/resources/TestMessages.properties,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- TestMessages.properties 5 Jul 2003 00:15:08 -0000 1.1 +++ TestMessages.properties 8 Jul 2003 00:16:58 -0000 1.2 @@ -13,12 +13,17 @@ Error Description JSVGCanvasHandler.message.error.could.not.load.svg = \ -Could not load SVG file: '{0}' +Could not load SVG file: {0} JSVGCanvasHandler.message.error.svg.render.failed = \ -Failed to render SVG file: '{0}' +Failed to render SVG file: {0} JSVGCanvasHandler.message.error.svg.update.failed = \ -Failed to handle SVG update: '{0}' +Failed to handle SVG update: {0} +NullSetSVGDocumentTest.message.error.image.not.cleared = \ +setSVGDocument(null) failed, display Image was not cleared from component. + +NullSetSVGDocumentTest.message.error.on.set = \ +setSVGDocument(null) failed with error: {0} 1.7 +0 -3 xml-batik/test-resources/org/apache/batik/test/svg/resources/Messages.properties Index: Messages.properties =================================================================== RCS file: /home/cvs/xml-batik/test-resources/org/apache/batik/test/svg/resources/Messages.properties,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- Messages.properties 5 Jul 2003 00:15:08 -0000 1.6 +++ Messages.properties 8 Jul 2003 00:16:58 -0000 1.7 @@ -9,9 +9,6 @@ # # Keys in the generated TestReport Entries # -JSVGCanvasHandler.entry.key.error.description = \ -Error Description - SVGRenderingAccuracyTest.entry.key.error.description = \ Error description 1.2 +146 -106 xml-batik/test-sources/org/apache/batik/swing/JSVGCanvasHandler.java Index: JSVGCanvasHandler.java =================================================================== RCS file: /home/cvs/xml-batik/test-sources/org/apache/batik/swing/JSVGCanvasHandler.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- JSVGCanvasHandler.java 5 Jul 2003 00:15:08 -0000 1.1 +++ JSVGCanvasHandler.java 8 Jul 2003 00:16:58 -0000 1.2 @@ -9,6 +9,7 @@ package org.apache.batik.swing; import java.awt.Dimension; +import java.awt.EventQueue; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; @@ -19,12 +20,14 @@ import org.apache.batik.test.Test; import org.apache.batik.test.TestReport; + import org.apache.batik.bridge.ScriptingEnvironment; import org.apache.batik.bridge.UpdateManager; import org.apache.batik.bridge.UpdateManagerEvent; import org.apache.batik.bridge.UpdateManagerListener; import org.apache.batik.script.Interpreter; import org.apache.batik.script.InterpreterException; +import org.apache.batik.util.RunnableQueue; import org.apache.batik.swing.gvt.GVTTreeRendererAdapter; import org.apache.batik.swing.gvt.GVTTreeRendererEvent; @@ -44,7 +47,9 @@ public interface Delegate { public String getName(); - public void canvasInit(JSVGCanvas canvas); + // Returns true if a load event was triggered. In this case + // the handler will wait for the load event to complete/fail. + public boolean canvasInit(JSVGCanvas canvas); public void canvasLoaded(JSVGCanvas canvas); public void canvasRendered(JSVGCanvas canvas); public boolean canvasUpdated(JSVGCanvas canvas); @@ -95,14 +100,15 @@ LoadListener ll = null; UpdateRenderListener url = null; - boolean renderFailed; - boolean loadFailed; - boolean abort; + boolean failed; + boolean abort = false; + boolean done = false; Object loadMonitor = new Object(); Object renderMonitor = new Object(); Delegate delegate; Test host; + String desc; public JSVGCanvasHandler(Test host, Delegate delegate) { this.host = host; @@ -113,119 +119,97 @@ public JSVGCanvas getCanvas() { return canvas; } public void runCanvas(String desc) { - DefaultTestReport report = new DefaultTestReport(host); - loadFailed = true; - renderFailed = true; - - frame = new JFrame(delegate.getName()); - canvas = new JSVGCanvas(); - frame.getContentPane().add(canvas); - frame.setSize(new Dimension(450, 500)); - frame.setVisible(true); - wl = new WindowAdapter() { - public void windowClosing(WindowEvent e) { - synchronized (loadMonitor) { - abort = true; - loadMonitor.notifyAll(); - } - synchronized (renderMonitor) { - abort = true; - renderMonitor.notifyAll(); - } - } - }; - frame.addWindowListener(wl); + this.desc = desc; + try { + EventQueue.invokeAndWait(new Runnable() { + public void run() { + frame = new JFrame(delegate.getName()); + canvas = new JSVGCanvas(); + frame.getContentPane().add(canvas); + frame.setSize(new Dimension(450, 500)); + wl = new WindowAdapter() { + public void windowClosing(WindowEvent e) { + synchronized (loadMonitor) { + abort = true; + loadMonitor.notifyAll(); + } + synchronized (renderMonitor) { + abort = true; + renderMonitor.notifyAll(); + } + } + }; + frame.addWindowListener(wl); + frame.setVisible(true); + + irl = new InitialRenderListener(); + canvas.addGVTTreeRendererListener(irl); + ll = new LoadListener(); + canvas.addSVGDocumentLoaderListener(ll); + }}); + } catch (Throwable t) { } + + if ( abort) return; - irl = new InitialRenderListener(); - canvas.addGVTTreeRendererListener(irl); - ll = new LoadListener(); - canvas.addSVGDocumentLoaderListener(ll); try { - - delegate.canvasInit(canvas); - synchronized (renderMonitor) { synchronized (loadMonitor) { - try { loadMonitor.wait(); } - catch(InterruptedException ie) { /* nothing */ } - if (abort || loadFailed) { - report.setErrorCode(ERROR_CANNOT_LOAD_SVG); - report.setDescription(new TestReport.Entry[] { - new TestReport.Entry - (fmt(ENTRY_KEY_ERROR_DESCRIPTION, null), - fmt(ERROR_CANNOT_LOAD_SVG, - new Object[]{desc})) - }); - report.setPassed(false); - delegate.failure(report); - return; + if (delegate.canvasInit(canvas)) { + checkLoad(); } - delegate.canvasLoaded(canvas); } - try { renderMonitor.wait(); } - catch(InterruptedException ie) { /* nothing */ } - if (abort || renderFailed) { - report.setErrorCode(ERROR_SVG_RENDER_FAILED); - report.setDescription(new TestReport.Entry[] { - new TestReport.Entry - (fmt(ENTRY_KEY_ERROR_DESCRIPTION, null), - fmt(ERROR_SVG_RENDER_FAILED, - new Object[]{desc})) - }); - report.setPassed(false); - delegate.failure(report); + if ( abort) return; + + checkRender(); + if ( abort) return; + + try { + EventQueue.invokeAndWait(new Runnable() { + public void run() { + updateManager = canvas.getUpdateManager(); + if (updateManager == null) + return; + url = new UpdateRenderListener(); + updateManager.addUpdateManagerListener(url); + }}); + } catch (Throwable t) { t.printStackTrace(); } + if ( abort) return; + + if (updateManager == null) return; - } - delegate.canvasRendered(canvas); - updateManager = canvas.getUpdateManager(); - if (updateManager != null) { - url = new UpdateRenderListener(); - updateManager.addUpdateManagerListener(url); - updateManager.getUpdateRunnableQueue().invokeLater - (new Runnable() { - UpdateManager um = updateManager; - public void run() { - ScriptingEnvironment scriptEnv; - scriptEnv = um.getScriptingEnvironment(); - Interpreter interp; - interp = scriptEnv.getInterpreter(); - interp.bindObject(REGARD_TEST_INSTANCE, - host); - try { - interp.evaluate(REGARD_START_SCRIPT); - } catch (InterpreterException ie) { - // Could not wait if no start script. - } - } - }); + bindHost(); - boolean done = false; - while (!done) { - try { renderMonitor.wait(); } - catch (InterruptedException ie) { /* nothing */ } - if (abort || renderFailed) { - report.setErrorCode(ERROR_SVG_UPDATE_FAILED); - report.setDescription(new TestReport.Entry[] { - new TestReport.Entry - (fmt(ENTRY_KEY_ERROR_DESCRIPTION, null), - fmt(ERROR_SVG_UPDATE_FAILED, - new Object[]{desc})) - }); - report.setPassed(false); - delegate.failure(report); - return; - } - done = delegate.canvasUpdated(canvas); - } + if ( abort) return; + + while (!done) { + checkUpdate(); + if ( abort) return; } } + } catch (Throwable t) { + t.printStackTrace(); } finally { delegate.canvasDone(canvas); dispose(); } } + + public void scriptDone() { + if (updateManager == null) return; + + updateManager.getUpdateRunnableQueue().invokeLater + (new Runnable() { + public void run() { + synchronized(renderMonitor) { + done = true; + failed = false; + renderMonitor.notifyAll(); + } + } + }); + } public void dispose() { if (frame != null) { @@ -242,17 +226,73 @@ canvas = null; frame = null; } - + + public void checkSomething(Object monitor, String errorCode) { + synchronized (monitor) { + failed = true; + try { monitor.wait(); } + catch(InterruptedException ie) { /* nothing */ } + if (abort || failed) { + DefaultTestReport report = new DefaultTestReport(host); + report.setErrorCode(errorCode); + report.setDescription(new TestReport.Entry[] { + new TestReport.Entry + (fmt(ENTRY_KEY_ERROR_DESCRIPTION, null), + fmt(errorCode, new Object[]{desc})) + }); + report.setPassed(false); + delegate.failure(report); + done = true; + return; + } + } + } + + public void checkLoad() { + checkSomething(loadMonitor, ERROR_CANNOT_LOAD_SVG); + delegate.canvasLoaded(canvas); + } + + public void checkRender() { + checkSomething(renderMonitor, ERROR_SVG_RENDER_FAILED); + delegate.canvasRendered(canvas); + } + + public void checkUpdate() { + checkSomething(renderMonitor, ERROR_SVG_UPDATE_FAILED); + if (!done) + done = delegate.canvasUpdated(canvas); + } + + public void bindHost() { + RunnableQueue rq; + rq = updateManager.getUpdateRunnableQueue(); + rq.invokeLater(new Runnable() { + UpdateManager um = updateManager; + public void run() { + ScriptingEnvironment scriptEnv; + scriptEnv = um.getScriptingEnvironment(); + Interpreter interp; + interp = scriptEnv.getInterpreter(); + interp.bindObject(REGARD_TEST_INSTANCE, + host); + try { + interp.evaluate(REGARD_START_SCRIPT); + } catch (InterpreterException ie) { + // Could not wait if no start script. + } + } + }); + } class UpdateRenderListener implements UpdateManagerListener { public void updateCompleted(UpdateManagerEvent e) { synchronized(renderMonitor){ - renderFailed = false; + failed = false; renderMonitor.notifyAll(); } } public void updateFailed(UpdateManagerEvent e) { synchronized(renderMonitor){ - renderFailed = true; renderMonitor.notifyAll(); } } @@ -266,7 +306,7 @@ class InitialRenderListener extends GVTTreeRendererAdapter { public void gvtRenderingCompleted(GVTTreeRendererEvent e) { synchronized(renderMonitor){ - renderFailed = false; + failed = false; renderMonitor.notifyAll(); } } @@ -288,7 +328,7 @@ class LoadListener extends SVGDocumentLoaderAdapter { public void documentLoadingCompleted(SVGDocumentLoaderEvent e) { synchronized(loadMonitor){ - loadFailed = false; + failed = false; loadMonitor.notifyAll(); } } 1.2 +37 -9 xml-batik/test-sources/org/apache/batik/swing/JSVGMemoryLeakTest.java Index: JSVGMemoryLeakTest.java =================================================================== RCS file: /home/cvs/xml-batik/test-sources/org/apache/batik/swing/JSVGMemoryLeakTest.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- JSVGMemoryLeakTest.java 5 Jul 2003 00:15:08 -0000 1.1 +++ JSVGMemoryLeakTest.java 8 Jul 2003 00:16:58 -0000 1.2 @@ -8,14 +8,22 @@ package org.apache.batik.swing; +import org.apache.batik.bridge.BridgeContext; +import org.apache.batik.bridge.UpdateManager; +import org.apache.batik.dom.svg.SVGOMElement; +import org.apache.batik.dom.svg.SVGContext; +import org.apache.batik.gvt.GraphicsNode; import org.apache.batik.test.DefaultTestReport; import org.apache.batik.test.TestReport; import org.apache.batik.test.MemoryLeakTest; -import javax.swing.SwingUtilities; -import javax.swing.JFrame; import java.io.File; import java.net.MalformedURLException; +import javax.swing.SwingUtilities; +import javax.swing.JFrame; + +import org.w3c.dom.Element; + /** * One line Class Desc @@ -38,6 +46,10 @@ JFrame theFrame; JSVGCanvas theCanvas; + public static String fmt(String key, Object []args) { + return TestMessages.formatMessage(key, args); + } + public TestReport doSomething() throws Exception { handler = new JSVGCanvasHandler(this, this); registerObjectDesc(handler, "Handler"); @@ -77,13 +89,27 @@ public void scriptDone() { synchronized (this) { done = true; - // The canvasUpdate will notify the handler that the - // canvas can be shut down. + handler.scriptDone(); + } + } + + public void registerElement(Element e, String desc) { + registerObjectDesc(e, desc); + UpdateManager um = theCanvas.getUpdateManager(); + BridgeContext bc = um.getBridgeContext(); + GraphicsNode gn = bc.getGraphicsNode(e); + if (gn != null) + registerObjectDesc(gn, desc+"_GN"); + if (e instanceof SVGOMElement) { + SVGOMElement svge = (SVGOMElement)e; + SVGContext svgctx = svge.getSVGContext(); + if (svgctx != null) + registerObjectDesc(svgctx, desc+"_CTX"); } } /* JSVGCanvasHandler.Delegate Interface */ - public void canvasInit(JSVGCanvas canvas) { + public boolean canvasInit(JSVGCanvas canvas) { // System.err.println("In Init"); theCanvas = canvas; theFrame = handler.getFrame(); @@ -95,17 +121,19 @@ } registerObjectDesc(canvas, "JSVGCanvas"); registerObjectDesc(handler.getFrame(), "JFrame"); + + return true; } public void canvasLoaded(JSVGCanvas canvas) { // System.err.println("Loaded"); - registerObjectDesc(canvas.getSVGDocument(), "SVG Document"); + registerObjectDesc(canvas.getSVGDocument(), "SVGDoc"); } public void canvasRendered(JSVGCanvas canvas) { // System.err.println("Rendered"); - registerObjectDesc(canvas.getGraphicsNode(), "Graphics Node Tree"); - registerObjectDesc(canvas.getUpdateManager(), "Update Manager"); + registerObjectDesc(canvas.getGraphicsNode(), "GVT"); + registerObjectDesc(canvas.getUpdateManager(), "updateManager"); } public boolean canvasUpdated(JSVGCanvas canvas) { 1.3 +1 -3 xml-batik/test-sources/org/apache/batik/swing/NullURITest.java Index: NullURITest.java =================================================================== RCS file: /home/cvs/xml-batik/test-sources/org/apache/batik/swing/NullURITest.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- NullURITest.java 10 Jun 2002 12:07:05 -0000 1.2 +++ NullURITest.java 8 Jul 2003 00:16:58 -0000 1.3 @@ -33,8 +33,6 @@ public static final String ERROR_COULD_NOT_RENDER_NULL_URI = "error.could.not.render.null.uri"; - public String testURI = "samples/anne.svg"; - public TestReport runImpl() throws Exception { final JFrame f = new JFrame(); final JSVGCanvas canvas = new JSVGCanvas(); 1.1 xml-batik/test-sources/org/apache/batik/swing/NullSetSVGDocumentTest.java Index: NullSetSVGDocumentTest.java =================================================================== /***************************************************************************** * Copyright (C) The Apache Software Foundation. All rights reserved. * * ------------------------------------------------------------------------- * * This software is published under the terms of the Apache Software License * * version 1.1, a copy of which has been included with this distribution in * * the LICENSE file. * *****************************************************************************/ package org.apache.batik.swing; import java.awt.EventQueue; import java.io.StringWriter; import java.io.PrintWriter; import org.apache.batik.dom.GenericDOMImplementation; import org.apache.batik.test.DefaultTestReport; import org.apache.batik.test.TestReport; import org.apache.batik.test.svg.JSVGRenderingAccuracyTest; import org.apache.batik.util.SVGConstants; import org.w3c.dom.Document; import org.w3c.dom.DOMImplementation; import org.w3c.dom.Element; /** * Test setDocument on JSVGComponent with non-Batik SVGOMDocument. * * This test constructs a generic Document with SVG content then it * ensures that when this is passed to JSVGComponet.setDocument it is * properly imported to an SVGOMDocument and rendered from there. * * @author <a href="mailto:[EMAIL PROTECTED]>l449433</a> * @version $Id: NullSetSVGDocumentTest.java,v 1.1 2003/07/08 00:16:58 deweese Exp $ */ public class NullSetSVGDocumentTest extends JSVGMemoryLeakTest { public NullSetSVGDocumentTest() { } public static final String TEST_NON_NULL_URI = "file:samples/anne.svg"; /** * Entry describing the error */ public static final String ENTRY_KEY_ERROR_DESCRIPTION = "JSVGCanvasHandler.entry.key.error.description"; /** * Entry describing the error */ public static final String ERROR_IMAGE_NOT_CLEARED = "NullSetSVGDocumentTest.message.error.image.not.cleared"; public static final String ERROR_ON_SET = "NullSetSVGDocumentTest.message.error.on.set"; /* JSVGCanvasHandler.Delegate Interface */ public boolean canvasInit(JSVGCanvas canvas) { theCanvas = canvas; theFrame = handler.getFrame(); canvas.setDocumentState(JSVGCanvas.ALWAYS_DYNAMIC); canvas.setURI(TEST_NON_NULL_URI); registerObjectDesc(canvas, "JSVGCanvas"); registerObjectDesc(handler.getFrame(), "JFrame"); return true; // We did trigger a load event. } public void canvasRendered(JSVGCanvas canvas) { super.canvasRendered(canvas); final JSVGCanvas c = canvas; try { EventQueue.invokeAndWait(new Runnable () { public void run() { c.setSVGDocument(null); }}); } catch (Throwable t) { StringWriter trace = new StringWriter(); t.printStackTrace(new PrintWriter(trace)); DefaultTestReport report = new DefaultTestReport(this); report.setErrorCode(ERROR_ON_SET); report.setDescription(new TestReport.Entry[] { new TestReport.Entry (fmt(ENTRY_KEY_ERROR_DESCRIPTION, null), fmt(ERROR_ON_SET, new Object[]{ trace.toString()})) }); report.setPassed(false); failReport = report; } // Check that the original SVG Document and GVT tree are cleared. checkObjects(new String[] { "SVGDoc", "GVT", "updateManager" }); } public boolean canvasUpdated(JSVGCanvas canvas) { return true; } public void canvasDone(JSVGCanvas canvas) { synchronized (this) { if (canvas.getOffScreen() == null) return; DefaultTestReport report = new DefaultTestReport(this); report.setErrorCode(ERROR_IMAGE_NOT_CLEARED); // It would be great to provide the image here // but it's a lot of work and this isn't _really_ // what we are testing. More testing that // everything works (no exceptions thrown). report.setDescription(new TestReport.Entry[] { new TestReport.Entry (fmt(ENTRY_KEY_ERROR_DESCRIPTION, null), fmt(ERROR_IMAGE_NOT_CLEARED, null))}); report.setPassed(false); failReport = report; return; } } }; 1.1 xml-batik/test-sources/org/apache/batik/swing/SetSVGDocumentTest.java Index: SetSVGDocumentTest.java =================================================================== /***************************************************************************** * Copyright (C) The Apache Software Foundation. All rights reserved. * * ------------------------------------------------------------------------- * * This software is published under the terms of the Apache Software License * * version 1.1, a copy of which has been included with this distribution in * * the LICENSE file. * *****************************************************************************/ package org.apache.batik.swing; import org.apache.batik.test.svg.JSVGRenderingAccuracyTest; import org.apache.batik.util.SVGConstants; import org.apache.batik.dom.GenericDOMImplementation; import org.w3c.dom.Document; import org.w3c.dom.DOMImplementation; import org.w3c.dom.Element; /** * Test setDocument on JSVGComponent with non-Batik SVGOMDocument. * * This test constructs a generic Document with SVG content then it * ensures that when this is passed to JSVGComponet.setDocument it is * properly imported to an SVGOMDocument and rendered from there. * * @author <a href="mailto:[EMAIL PROTECTED]>l449433</a> * @version $Id: SetSVGDocumentTest.java,v 1.1 2003/07/08 00:16:58 deweese Exp $ */ public class SetSVGDocumentTest extends JSVGRenderingAccuracyTest { public SetSVGDocumentTest() { } protected String[] breakSVGFile(String svgFile){ if(svgFile == null) { throw new IllegalArgumentException(svgFile); } String [] ret = new String[3]; ret[0] = "test-resources/org/apache/batik/test/svg/"; ret[1] = "SetSVGDocumentTest"; ret[2] = ".svg"; return ret; } /* JSVGCanvasHandler.Delegate Interface */ public boolean canvasInit(JSVGCanvas canvas) { DOMImplementation impl = GenericDOMImplementation.getDOMImplementation(); Document doc = impl.createDocument(SVGConstants.SVG_NAMESPACE_URI, SVGConstants.SVG_SVG_TAG, null); Element e = doc.createElementNS(SVGConstants.SVG_NAMESPACE_URI, SVGConstants.SVG_RECT_TAG); e.setAttribute("x", "10"); e.setAttribute("y", "10"); e.setAttribute("width", "100"); e.setAttribute("height", "50"); e.setAttribute("fill", "crimson"); doc.getDocumentElement().appendChild(e); e = doc.createElementNS(SVGConstants.SVG_NAMESPACE_URI, SVGConstants.SVG_CIRCLE_TAG); e.setAttribute("cx", "55"); e.setAttribute("cy", "35"); e.setAttribute("r", "30"); e.setAttribute("fill", "gold"); doc.getDocumentElement().appendChild(e); canvas.setDocument(doc); return false; // We didn't trigger a load event. } public boolean canvasUpdated(JSVGCanvas canvas) { return true; } }; 1.3 +117 -34 xml-batik/test-sources/org/apache/batik/test/MemoryLeakTest.java Index: MemoryLeakTest.java =================================================================== RCS file: /home/cvs/xml-batik/test-sources/org/apache/batik/test/MemoryLeakTest.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- MemoryLeakTest.java 5 Jul 2003 00:15:08 -0000 1.2 +++ MemoryLeakTest.java 8 Jul 2003 00:16:58 -0000 1.3 @@ -8,8 +8,10 @@ package org.apache.batik.test; -import java.util.Set; -import java.util.HashSet; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.HashMap; import java.util.Iterator; import org.apache.batik.test.AbstractTest; @@ -28,11 +30,14 @@ */ public abstract class MemoryLeakTest extends AbstractTest { - // I know that 60 seems _really_ high but it turns out - // That the GraphicsNodeTree was not being cleared when I - // tested with as high as 36. So I would leave it at 60 - // (why so large I don't know). - final static int NUM_GC=60; + // I know that 120 seems _really_ high but it turns out + // That the "GraphicsNodeTree" was not being cleared when I + // tested with as high as 60. So I would leave it at 120 + // (why so large I don't know) - it will bail if the all + // the objects of interest are collected sooner so the runtime + // is really only a concern for failures. + final static int NUM_GC=120; + final static String ERROR_OBJS_NOT_CLEARED = "MemoryLeakTest.message.error.objs.not.cleared"; @@ -46,61 +51,139 @@ public MemoryLeakTest() { } - Set objs = new HashSet(); + Map objs = new HashMap(); + List entries = new ArrayList(); public void registerObject(Object o) { synchronized (objs) { - objs.add(new WeakRef(o)); + String desc = o.toString(); + objs.put(desc, new WeakRef(o, desc)); } } public void registerObjectDesc(Object o, String desc) { synchronized (objs) { - objs.add(new WeakRef(o, desc)); + objs.put(desc, new WeakRef(o, desc)); } } + public boolean checkObject(String desc) { + String [] strs = new String[1]; + strs[0] = desc; + return checkObjects(strs); + } - public TestReport runImpl() throws Exception { - TestReport ret = doSomething(); - if ((ret != null) && !ret.hasPassed()) - return ret; - + public boolean checkObjects(String [] descs) { for (int i=0; i<NUM_GC; i++) { System.gc(); + boolean passed = true; + for (int j=0; j< descs.length; j++) { + String desc = descs[j]; + WeakRef wr = (WeakRef)objs.get(desc); + if ((wr != null) && (wr.get() != null)) { + passed = false; + break; + } + } + if (passed) return true; } StringBuffer sb = new StringBuffer(); - int count = 0; synchronized (objs) { - Iterator i = objs.iterator(); - while (i.hasNext()) { - WeakRef wr = (WeakRef)i.next(); + boolean passed = true; + for (int j=0; j< descs.length; j++) { + String desc = descs[j]; + WeakRef wr = (WeakRef)objs.get(desc); + if ((wr == null) || (wr.get() == null)) continue; + if (!passed) + sb.append(","); // Already put one obj out + passed = false; + sb.append("'"); + sb.append(wr.getDesc()); + sb.append("'"); + } + } + + String objStr = sb.toString(); + TestReport.Entry entry = new TestReport.Entry + (fmt(ERROR_DESCRIPTION, null), + fmt(ERROR_OBJS_NOT_CLEARED, new Object[]{objStr})); + entries.add(entry); + + if (objStr.length() > 40) + objStr = objStr.substring(0,40) + "..." ; + System.err.print(">>>>> Objects not cleared: " + objStr + "\n"); + return false; + } + + public boolean checkObjectsList(List descs) { + String [] strs = new String[descs.size()]; + descs.toArray(strs); + return checkObjects(strs); + } + + public boolean checkAllObjects() { + for (int i=0; i<NUM_GC; i++) { + System.gc(); + synchronized (objs) { + boolean passed = true; + Iterator iter = objs.values().iterator(); + while (iter.hasNext()) { + WeakRef wr = (WeakRef)iter.next(); + Object o = wr.get(); + if (o != null) { + passed = false; + break; + } + } + if (passed) return true; + } + } + + StringBuffer sb = new StringBuffer(); + synchronized (objs) { + boolean passed = true; + Iterator iter = objs.values().iterator(); + while (iter.hasNext()) { + WeakRef wr = (WeakRef)iter.next(); Object o = wr.get(); if (o == null) continue; - if (count != 0) + if (!passed) sb.append(","); - + passed = false; sb.append(wr.getDesc()); - count++; } + if (passed) return true; } - DefaultTestReport report = new DefaultTestReport(this); - if (count == 0) { - report.setPassed(true); - return report; - } String objStr = sb.toString(); - report.setErrorCode(ERROR_OBJS_NOT_CLEARED); - report.setDescription(new TestReport.Entry[] { - new TestReport.Entry + TestReport.Entry entry = new TestReport.Entry (fmt(ERROR_DESCRIPTION, null), - fmt(ERROR_OBJS_NOT_CLEARED, new Object[]{objStr})) - }); + fmt(ERROR_OBJS_NOT_CLEARED, new Object[]{objStr})); + entries.add(entry); + if (objStr.length() > 40) objStr = objStr.substring(0,40) + "..." ; System.err.print(">>>>> Objects not cleared: " + objStr + "\n"); + return false; + } + + public TestReport runImpl() throws Exception { + TestReport ret = doSomething(); + if ((ret != null) && !ret.hasPassed()) + return ret; + + checkAllObjects(); + + DefaultTestReport report = new DefaultTestReport(this); + if (entries.size() == 0) { + report.setPassed(true); + return report; + } + report.setErrorCode(ERROR_OBJS_NOT_CLEARED); + report.setDescription + ((TestReport.Entry[])entries.toArray + (new TestReport.Entry[entries.size()])); report.setPassed(false); return report; } @@ -122,7 +205,7 @@ public void cleared() { synchronized (objs) { - objs.remove(this); + objs.remove(desc); } } 1.3 +9 -6 xml-batik/test-sources/org/apache/batik/test/svg/JSVGRenderingAccuracyTest.java Index: JSVGRenderingAccuracyTest.java =================================================================== RCS file: /home/cvs/xml-batik/test-sources/org/apache/batik/test/svg/JSVGRenderingAccuracyTest.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- JSVGRenderingAccuracyTest.java 5 Jul 2003 00:15:08 -0000 1.2 +++ JSVGRenderingAccuracyTest.java 8 Jul 2003 00:16:58 -0000 1.3 @@ -55,15 +55,18 @@ FileOutputStream fos; TestReport failReport = null; boolean done; + JSVGCanvasHandler handler = null; public TestReport encode(URL srcURL, FileOutputStream fos) { this.srcURL = srcURL; this.fos = fos; - JSVGCanvasHandler handler = new JSVGCanvasHandler(this, this); + handler = new JSVGCanvasHandler(this, this); done = false; handler.runCanvas(srcURL.toString()); - + + handler = null; + if (failReport != null) return failReport; DefaultTestReport report = new DefaultTestReport(this); @@ -74,14 +77,14 @@ public void scriptDone() { synchronized (this) { done = true; - // The canvasUpdate will notify the handler that the - // canvas can be shut down. + handler.scriptDone(); } } /* JSVGCanvasHandler.Delegate Interface */ - public void canvasInit(JSVGCanvas canvas) { + public boolean canvasInit(JSVGCanvas canvas) { canvas.setURI(srcURL.toString()); + return true; } public void canvasLoaded(JSVGCanvas canvas) {
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]