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>&lt;text&gt; children 'onload'</title>
  -
  -  <text x="50%" y="45" class="title">&lt;text&gt; 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]

Reply via email to