deweese 2005/02/28 09:37:19 Modified: . build.xml samples/tests/spec/scripting addDescOnClick.svg pathLength.svg sources/org/apache/batik/dom AbstractDocument.java AbstractElement.java GenericDocument.java sources/org/apache/batik/dom/svg SVGOMDocument.java SVGOMSVGElement.java test-resources/org/apache/batik/test samplesRendering.xml Added: samples/tests/spec/scripting getElementById.svg test-references/samples/tests/spec/scripting getElementById.png Log: 1) Document.getElementById now uses a Hashtable to speedup lookups. 2) Regard now uses -Xincgc because the memory leak tests behave better. Revision Changes Path 1.160 +2 -1 xml-batik/build.xml Index: build.xml =================================================================== RCS file: /home/cvs/xml-batik/build.xml,v retrieving revision 1.159 retrieving revision 1.160 diff -u -r1.159 -r1.160 --- build.xml 22 Feb 2005 09:12:54 -0000 1.159 +++ build.xml 28 Feb 2005 17:37:18 -0000 1.160 @@ -1127,6 +1127,7 @@ description="Runs test suite whose file or uri is passed as an input"> <java fork="yes" classname="${class-prefix}.test.xml.XMLTestSuiteRunner"> + <jvmarg value="-Xincgc" /> <!-- <jvmarg value="-Xrunhprof:format=b" /> --> <!-- <jvmarg value="-Xrunhprof:net=localhost:1234,format=b" /> --> <jvmarg value="-Xmx512m"/> <jvmarg value="-Xms64m"/> 1.2 +2 -2 xml-batik/samples/tests/spec/scripting/addDescOnClick.svg Index: addDescOnClick.svg =================================================================== RCS file: /home/cvs/xml-batik/samples/tests/spec/scripting/addDescOnClick.svg,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- addDescOnClick.svg 27 Feb 2005 02:08:51 -0000 1.1 +++ addDescOnClick.svg 28 Feb 2005 17:37:18 -0000 1.2 @@ -4,7 +4,7 @@ <!-- - Copyright 2002 The Apache Software Foundation + Copyright 2005 The Apache Software Foundation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 1.2 +2 -2 xml-batik/samples/tests/spec/scripting/pathLength.svg Index: pathLength.svg =================================================================== RCS file: /home/cvs/xml-batik/samples/tests/spec/scripting/pathLength.svg,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- pathLength.svg 27 Feb 2005 02:08:51 -0000 1.1 +++ pathLength.svg 28 Feb 2005 17:37:18 -0000 1.2 @@ -4,7 +4,7 @@ <!-- - Copyright 2002 The Apache Software Foundation + Copyright 2005 The Apache Software Foundation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 1.1 xml-batik/samples/tests/spec/scripting/getElementById.svg Index: getElementById.svg =================================================================== <?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> <!-- Copyright 2005 The Apache Software Foundation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <!-- ====================================================================== --> <!-- Test of the getElementById method --> <!-- --> <!-- @author [EMAIL PROTECTED] --> <!-- @version $Id: getElementById.svg,v 1.1 2005/02/28 17:37:18 deweese Exp $ --> <!-- ====================================================================== --> <?xml-stylesheet type="text/css" href="../../resources/style/test.css" ?> <svg id="body" width="450" height="500" viewBox="0 0 450 500" onload="doTest()" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <title>Test of 'getElementById' method</title> <text x="50%" y="45" class="title">Test of 'getElementById' method</text> <script type="text/ecmascript"> var svgns = "http://www.w3.org/2000/svg"; function setText(id, text, color) { var tspan = document.getElementById(id); tspan.appendChild(document.createTextNode(text)); tspan.setAttribute("fill", color); } function checkTest(e, base, id, tId) { if (e == base.getElementById(id)) setText(tId, "success", "green"); else setText(tId, "failed", "red"); } function doTest() { var g = document.getElementById("group"); var id1 = g.firstChild; var id2 = id1.nextSibling; var id3 = id2.nextSibling; var id4 = id3.nextSibling; var svg1 = id4.nextSibling; var id5 = svg1.firstChild; var id6 = id5.nextSibling; var id7 = svg1.nextSibling; checkTest(id1, document, "id1", "t1"); checkTest(id2, document, "id2", "t2"); checkTest(null, document, "undefined", "t3"); checkTest(svg1, document, "svg1", "t4"); checkTest(svg1, svg1, "svg1", "t5"); checkTest(id5, document, "id5", "t6"); checkTest(id5, svg1, "id5", "t7"); checkTest(id6, svg1, "id6", "t8"); checkTest(id7, svg1, "id7", "t9"); id2.setAttribute("id", "d1"); checkTest(id2, document, "d1", "t10"); var attr = document.createAttribute("id"); attr.setValue("d2"); id3.setAttributeNode(attr); checkTest(id3, document, "d2", "t11"); checkTest(null, document, "id3", "t12"); attr.setValue("d3"); checkTest(id3, document, "d3", "t13"); id4.removeAttribute("id"); checkTest(null, document, "id4", "t14"); svg1.parentNode.removeChild(svg1); checkTest(null, document, "id5", "t15"); checkTest(id5, svg1, "id5", "t16"); var svg2 = document.createElementNS(svgns, "svg"); var id8 = document.createElementNS(svgns, "desc"); svg2.appendChild(id8); id8.setAttribute("id", "id8"); checkTest(null, document, "id8", "t17"); checkTest(null, svg1, "id8", "t18"); checkTest(id8, svg2, "id8", "t19"); var id9 = document.createElementNS(svgns, "desc"); id9.setAttribute("id", "id9"); svg2.appendChild(id9); checkTest(null, document, "id9", "t20"); checkTest(null, svg1, "id9", "t21"); checkTest(id9, svg2, "id9", "t22"); } </script> <g id="group"><rect id="id1" x="10" y="60" width="50" height="50" fill="gold" stroke="black" /><rect id="id2" x="70" y="60" width="50" height="50" fill="crimson" stroke="black" /><rect id="id3" x="130" y="60" width="50" height="50" fill="gold" stroke="black" /><rect id="id4" x="190" y="60" width="50" height="50" fill="crimson" stroke="black" /><svg id="svg1" x="0" y="0" width="450" height="500" ><rect id="id5" x="250" y="60" width="50" height="50" fill="crimson" stroke="black" /><rect id="id6" x="310" y="60" width="50" height="50" fill="gold" stroke="black" /></svg><rect id="id7" x="370" y="60" width="50" height="50" fill="gold" stroke="black"/> <text x="60" y="140" text-anchor="end" >Test 1: <tspan id="t1" x="65" text-anchor="start"/></text> <text x="60" y="160" text-anchor="end" >Test 2: <tspan id="t2" x="65" text-anchor="start"/></text> <text x="60" y="180" text-anchor="end" >Test 3: <tspan id="t3" x="65" text-anchor="start"/></text> <text x="60" y="200" text-anchor="end" >Test 4: <tspan id="t4" x="65" text-anchor="start"/></text> <text x="60" y="220" text-anchor="end" >Test 5: <tspan id="t5" x="65" text-anchor="start"/></text> <text x="60" y="240" text-anchor="end" >Test 6: <tspan id="t6" x="65" text-anchor="start"/></text> <text x="60" y="260" text-anchor="end" >Test 7: <tspan id="t7" x="65" text-anchor="start"/></text> <text x="60" y="280" text-anchor="end" >Test 8: <tspan id="t8" x="65" text-anchor="start"/></text> <text x="60" y="300" text-anchor="end" >Test 9: <tspan id="t9" x="65" text-anchor="start"/></text> <text x="60" y="320" text-anchor="end" >Test 10: <tspan id="t10" x="65" text-anchor="start"/></text> <text x="60" y="340" text-anchor="end" >Test 11: <tspan id="t11" x="65" text-anchor="start"/></text> <text x="220" y="140" text-anchor="end" >Test 12: <tspan id="t12" x="225" text-anchor="start"/></text> <text x="220" y="160" text-anchor="end" >Test 13: <tspan id="t13" x="225" text-anchor="start"/></text> <text x="220" y="180" text-anchor="end" >Test 14: <tspan id="t14" x="225" text-anchor="start"/></text> <text x="220" y="200" text-anchor="end" >Test 15: <tspan id="t15" x="225" text-anchor="start"/></text> <text x="220" y="220" text-anchor="end" >Test 16: <tspan id="t16" x="225" text-anchor="start"/></text> <text x="220" y="240" text-anchor="end" >Test 17: <tspan id="t17" x="225" text-anchor="start"/></text> <text x="220" y="260" text-anchor="end" >Test 18: <tspan id="t18" x="225" text-anchor="start"/></text> <text x="220" y="280" text-anchor="end" >Test 19: <tspan id="t19" x="225" text-anchor="start"/></text> <text x="220" y="300" text-anchor="end" >Test 20: <tspan id="t20" x="225" text-anchor="start"/></text> <text x="220" y="320" text-anchor="end" >Test 21: <tspan id="t21" x="225" text-anchor="start"/></text> <text x="220" y="340" text-anchor="end" >Test 22: <tspan id="t22" x="225" text-anchor="start"/></text> </g> </svg> 1.26 +192 -1 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.25 retrieving revision 1.26 diff -u -r1.25 -r1.26 --- AbstractDocument.java 22 Feb 2005 09:12:57 -0000 1.25 +++ AbstractDocument.java 28 Feb 2005 17:37:18 -0000 1.26 @@ -21,7 +21,12 @@ import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.MissingResourceException; import java.util.WeakHashMap; @@ -29,6 +34,7 @@ import org.apache.batik.dom.traversal.TraversalSupport; import org.apache.batik.i18n.Localizable; import org.apache.batik.i18n.LocalizableSupport; +import org.apache.batik.util.CleanerThread; import org.apache.batik.util.SoftDoublyIndexedTable; import org.w3c.dom.Attr; import org.w3c.dom.DOMException; @@ -102,6 +108,15 @@ protected transient WeakHashMap elementsByTagNamesNS; /** + * The elementsById lists. + * This is keyed on 'id'. the entry is either + * a IdSoftReference to the element or a List of + * IdSoftReferences (if there is more than one element + * owned by this document with a particular 'id'). + */ + protected transient Map elementsById; + + /** * Creates a new document. */ protected AbstractDocument() { @@ -322,6 +337,182 @@ return n; } + public abstract boolean isID(Attr node); + + /** + * <b>DOM</b>: Implements [EMAIL PROTECTED] + * org.w3c.dom.Document#getElementById(String)}. + */ + public Element getElementById(String id) { + return getChildElementById(getDocumentElement(), id); + } + + /** + * Finds an element that is in the same document fragment as + * 'requestor' that has 'id'. + */ + public Element getChildElementById(Node requestor, String id) { + if ((id == null) || (id.length()==0)) return null; + if (elementsById == null) return null; + + Node root = getRoot(requestor); + + Object o = elementsById.get(id); + if (o == null) return null; + if (o instanceof IdSoftRef) { + o = ((IdSoftRef)o).get(); + if (o == null) { + elementsById.remove(id); + return null; + } + Element e = (Element)o; + if (getRoot(e) == root) + return e; + return null; + } + + // Not a IdSoftRef so it must be a list. + List l = (List)o; + Iterator li = l.iterator(); + while (li.hasNext()) { + IdSoftRef sr = (IdSoftRef)li.next(); + o = sr.get(); + if (o == null) { + li.remove(); + } else { + Element e = (Element)o; + if (getRoot(e) == root) + return e; + } + } + return null; + } + + protected Node getRoot(Node n) { + Node r = n; + while (n != null) { + r = n; + n = n.getParentNode(); + } + return r; + } + + protected class IdSoftRef extends CleanerThread.SoftReferenceCleared { + String id; + List list; + IdSoftRef(Object o, String id) { + super(o); + this.id = id; + } + IdSoftRef(Object o, String id, List list) { + super(o); + this.id = id; + this.list = list; + } + public void setList(List list) { + this.list = list; + } + public void cleared() { + if (elementsById == null) return; + synchronized (elementsById) { + if (list != null) + list.remove(this); + else { + Object o = elementsById.remove(id); + if (o != this) // oops not us! + elementsById.put(id, o); + } + } + } + } + + /** + * Remove the mapping for <tt>element</tt> to <tt>id</tt> + */ + public void removeIdEntry(Element e, String id) { + // Remove old Id mapping if we have one. + if (id == null) return; + if (elementsById == null) return; + + synchronized (elementsById) { + Object o = elementsById.get(id); + if (o == null) return; + + if (o instanceof IdSoftRef) { + elementsById.remove(id); + return; + } + + List l = (List)o; + Iterator li = l.iterator(); + while (li.hasNext()) { + IdSoftRef ip = (IdSoftRef)li.next(); + o = ip.get(); + if (o == null) { + li.remove(); + } else if (e == o) { + li.remove(); + break; + } + } + + if (l.size() == 0) + elementsById.remove(id); + } + } + + public void addIdEntry(Element e, String id) { + if (id == null) return; + + if (elementsById == null) { + Map tmp = new HashMap(); + synchronized (tmp) { + elementsById = tmp; + elementsById.put(id, new IdSoftRef(e, id)); + } + return; + } + + synchronized (elementsById) { + // Add new Id mapping. + Object o = elementsById.get(id); + if (o == null) { + elementsById.put(id, new IdSoftRef(e, id)); + return; + } + if (o instanceof IdSoftRef) { + IdSoftRef ip = (IdSoftRef)o; + Object r = ip.get(); + if (r == null) { // reference is gone so replace it. + elementsById.put(id, new IdSoftRef(e, id)); + return; + } + + // Create new List for this id. + List l = new ArrayList(4); + ip.setList(l); + l.add(ip); + l.add(new IdSoftRef(e, id, l)); + elementsById.put(id, l); + return; + } + + List l = (List)o; + l.add(new IdSoftRef(e, id, l)); + } + } + + public void updateIdEntry(Element e, String oldId, String newId) { + if ((oldId == newId) || + ((oldId != null) && (oldId.equals(newId)))) + return; + + removeIdEntry(e, oldId); + + addIdEntry(e, newId); + } + + /** * Returns an ElementsByTagName object from the cache, if any. */ 1.27 +7 -1 xml-batik/sources/org/apache/batik/dom/AbstractElement.java Index: AbstractElement.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/dom/AbstractElement.java,v retrieving revision 1.26 retrieving revision 1.27 diff -u -r1.26 -r1.27 --- AbstractElement.java 22 Feb 2005 09:12:57 -0000 1.26 +++ AbstractElement.java 28 Feb 2005 17:37:18 -0000 1.27 @@ -489,14 +489,20 @@ String newv, short change) { switch (change) { case MutationEvent.ADDITION: + if (ownerDocument.isID(node)) + ownerDocument.addIdEntry(this, newv); attrAdded(node, newv); break; case MutationEvent.MODIFICATION: + if (ownerDocument.isID(node)) + ownerDocument.updateIdEntry(this, oldv, newv); attrModified(node, oldv, newv); break; default: // MutationEvent.REMOVAL: + if (ownerDocument.isID(node)) + ownerDocument.removeIdEntry(this, oldv); attrRemoved(node, oldv); } AbstractDocument doc = getCurrentDocument(); 1.10 +14 -39 xml-batik/sources/org/apache/batik/dom/GenericDocument.java Index: GenericDocument.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/dom/GenericDocument.java,v retrieving revision 1.9 retrieving revision 1.10 diff -u -r1.9 -r1.10 --- GenericDocument.java 22 Feb 2005 09:12:58 -0000 1.9 +++ GenericDocument.java 28 Feb 2005 17:37:18 -0000 1.10 @@ -39,6 +39,10 @@ */ public class GenericDocument extends AbstractDocument { + + /** Local name for 'id' attributes. */ + protected final static String ATTR_ID = "id"; + /** * Is this document immutable? */ @@ -72,6 +76,15 @@ } /** + * Returns true if the given Attr node represents an 'id' + * for this document. + */ + public boolean isID(Attr node) { + if (node.getNamespaceURI() != null) return false; + return ATTR_ID.equals(node.getNodeName()); + } + + /** * <b>DOM</b>: Implements [EMAIL PROTECTED] * org.w3c.dom.Document#createElement(String)}. */ @@ -125,44 +138,6 @@ /** * <b>DOM</b>: Implements [EMAIL PROTECTED] - * org.w3c.dom.Document#getElementById(String)}. - */ - public Element getElementById(String elementId) { - if (elementId == null || elementId.equals("")) { - return null; - } - Element e = getDocumentElement(); - if (e == null) { - return null; - } - return getById(elementId, e); - } - - /** - * An auxiliary method used by getElementById. - */ - protected static Element getById(String id, Node node) { - if (!(node instanceof Element)) { - return null; - } - - Element e = (Element)node; - if (e.getAttribute("id").equals(id)) { - return e; - } - for (Node n = node.getFirstChild(); - n != null; - n = n.getNextSibling()) { - Element result = getById(id, n); - if (result != null) { - return result; - } - } - return null; - } - - /** - * <b>DOM</b>: Implements [EMAIL PROTECTED] * org.w3c.dom.Document#createAttribute(String)}. */ public Attr createAttribute(String name) throws DOMException { 1.56 +6 -32 xml-batik/sources/org/apache/batik/dom/svg/SVGOMDocument.java Index: SVGOMDocument.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/dom/svg/SVGOMDocument.java,v retrieving revision 1.55 retrieving revision 1.56 diff -u -r1.55 -r1.56 --- SVGOMDocument.java 22 Feb 2005 09:13:01 -0000 1.55 +++ SVGOMDocument.java 28 Feb 2005 17:37:18 -0000 1.56 @@ -298,38 +298,12 @@ } /** - * <b>DOM</b>: Implements [EMAIL PROTECTED] Document#getElementById(String)}. + * Returns true if the given Attr node represents an 'id' + * for this document. */ - public Element getElementById(String elementId) { - if (elementId == null || elementId.equals("")) { - return null; - } - Element e = getDocumentElement(); - if (e == null) { - return null; - } - return getById(elementId, e); - } - - /** - * An auxiliary method used by getElementById. - */ - protected static Element getById(String id, Node node) { - if (node.getNodeType() == Node.ELEMENT_NODE) { - Element elt = (Element)node; - if (elt.getAttributeNS(null, "id").equals(id)) { - return elt; - } - } - for (Node n = node.getFirstChild(); - n != null; - n = n.getNextSibling()) { - Element result = getById(id, n); - if (result != null) { - return result; - } - } - return null; + public boolean isID(Attr node) { + if (node.getNamespaceURI() != null) return false; + return SVG_ID_ATTRIBUTE.equals(node.getNodeName()); } // AbstractDocument /////////////////////////////////////////////// 1.31 +2 -2 xml-batik/sources/org/apache/batik/dom/svg/SVGOMSVGElement.java Index: SVGOMSVGElement.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/dom/svg/SVGOMSVGElement.java,v retrieving revision 1.30 retrieving revision 1.31 diff -u -r1.30 -r1.31 --- SVGOMSVGElement.java 22 Feb 2005 09:13:01 -0000 1.30 +++ SVGOMSVGElement.java 28 Feb 2005 17:37:18 -0000 1.31 @@ -393,7 +393,7 @@ return tr; } public Element getElementById ( String elementId ) { - return ((SVGOMDocument)getDocument()).getElementById(elementId); + return ownerDocument.getChildElementById(this, elementId); } // SVGLocatable /////////////////////////////////////////////////////// 1.1 xml-batik/test-references/samples/tests/spec/scripting/getElementById.png <<Binary file>> 1.127 +2 -1 xml-batik/test-resources/org/apache/batik/test/samplesRendering.xml Index: samplesRendering.xml =================================================================== RCS file: /home/cvs/xml-batik/test-resources/org/apache/batik/test/samplesRendering.xml,v retrieving revision 1.126 retrieving revision 1.127 diff -u -r1.126 -r1.127 --- samplesRendering.xml 27 Feb 2005 02:08:52 -0000 1.126 +++ samplesRendering.xml 28 Feb 2005 17:37:18 -0000 1.127 @@ -364,6 +364,7 @@ <test id="samples/tests/spec/scripting/enclosureList.svg" /> <test id="samples/tests/spec/scripting/enclosureList2.svg" /> <test id="samples/tests/spec/scripting/fill.svg" /> + <test id="samples/tests/spec/scripting/getElementById.svg" /> <test id="samples/tests/spec/scripting/image.svg" /> <test id="samples/tests/spec/scripting/imageRefUpdate.svg" /> <test id="samples/tests/spec/scripting/imageraster.svg" />
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]