You are viewing a plain text version of this content. The canonical link for it is here.
Posted to batik-dev@xmlgraphics.apache.org by de...@apache.org on 2005/02/27 03:08:52 UTC

cvs commit: xml-batik/test-resources/org/apache/batik/test interactiveSamples.xml samplesRendering.xml

deweese     2005/02/26 18:08:52

  Modified:    resources/org/apache/batik/dom/svg/resources
                        Messages.properties
               sources/org/apache/batik/bridge
                        AbstractGraphicsNodeBridge.java BridgeContext.java
                        BridgeEventSupport.java SVGDescElementBridge.java
                        SVGKernElementBridge.java SVGPathElementBridge.java
                        SVGTitleElementBridge.java
               sources/org/apache/batik/dom/svg SVGLocatableSupport.java
                        SVGOMPathElement.java
               sources/org/apache/batik/ext/awt/geom Linear.java
                        PathLength.java
               sources/org/apache/batik/gvt/renderer BasicTextPainter.java
               sources/org/apache/batik/gvt/text Mark.java
               sources/org/apache/batik/swing JSVGCanvas.java
               sources/org/apache/batik/swing/svg JSVGComponent.java
               test-resources/org/apache/batik/test interactiveSamples.xml
                        samplesRendering.xml
  Added:       samples/tests/spec/scripting addDescOnClick.svg
                        pathLength.svg
               sources/org/apache/batik/bridge
                        SVGDescriptiveElementBridge.java
               sources/org/apache/batik/dom/svg SVGPathContext.java
                        SVGPathSupport.java
               test-references/samples/tests/spec/scripting pathLength.png
  Log:
  1) Fixed bug in handling kerning elements with multiple glyph entries
     in g/u 1or2.
  2) title and desc changes are now dynamically tracked.
     New test for this.
  3) getTotalLength, and getPointAtLength are now implemented.
     New test for this.
  4) The Marker interface now has a 'getCharIndex()' method to
     get the index of the character the Mark is associated with.
  
  Revision  Changes    Path
  1.9       +4 -0      xml-batik/resources/org/apache/batik/dom/svg/resources/Messages.properties
  
  Index: Messages.properties
  ===================================================================
  RCS file: /home/cvs/xml-batik/resources/org/apache/batik/dom/svg/resources/Messages.properties,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- Messages.properties	18 Aug 2004 07:11:32 -0000	1.8
  +++ Messages.properties	27 Feb 2005 02:08:51 -0000	1.9
  @@ -48,3 +48,7 @@
   
   readonly.rect = \
   This SVGRect is readonly.
  +
  +readonly.point = \
  +This SVGPoint is readonly.
  +
  
  
  
  1.1                  xml-batik/samples/tests/spec/scripting/addDescOnClick.svg
  
  Index: addDescOnClick.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 2002  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.
  
  -->
  <!-- ====================================================================== -->
  <!-- Append/Remove desc/title test                                          -->
  <!--                                                                        -->
  <!-- @author deweese@apache.org                                             -->
  <!-- @version $Id: addDescOnClick.svg,v 1.1 2005/02/27 02:08:51 deweese Exp $ -->
  <!-- ====================================================================== -->
  
  <?xml-stylesheet type="text/css" href="../../resources/style/test.css" ?>  
  
  <svg xmlns="http://www.w3.org/2000/svg" 
       xmlns:xlink="http://www.w3.org/1999/xlink"
       id="body" width="450" height="500" viewBox="0 0 450 500">
  
      <title>Add Desc element "onClick"</title>
  
      <text x="50%" y="45" class="title">Add Desc element "onClick"</text>
  
      <script type="text/ecmascript">
  
      var svgNamespaceURI = "http://www.w3.org/2000/svg";
  
      function addChild(evt, tag) {
          var r = evt.target;
          var document = r.ownerDocument;
          var e = document.createElementNS(svgNamespaceURI, tag);
          e.appendChild(document.createTextNode("Dynamic: " + tag));
          r.appendChild(e);
      }
  
      var desc  = document.getElementById("foo");
      var newD = document.createTextNode("Text 1");
      var oldD = desc.firstChild;
  
      function toggleDesc() {
         desc.replaceChild(newD, oldD);
         var tmp = newD; newD=oldD; oldD=tmp;
         setTimeout("toggleDesc()", 1000);
      }
  
      var title  = document.getElementById("bar");
      var newT = document.createTextNode("Title 2");
      var oldT = title.firstChild;
  
      function toggleTitle() {
         title.replaceChild(newT, oldT);
         var tmp = newT; newT=oldT; oldT=tmp;
         setTimeout("toggleTitle()", 1000);
      }
  
      toggleDesc();
      toggleTitle();
  
      var elT = document.getElementById("title");
      var tglTitle = elT.firstChild;
      var elD = document.getElementById("desc");
      var tglDesc = elD.firstChild;
  
      function toggleShowTitle() {
        if (elT.firstChild) 
           elT.removeChild(tglTitle);
        else
           elT.appendChild(tglTitle);
         setTimeout("toggleShowTitle()", 1000);
      }
      function toggleShowDesc() {
        if (elD.firstChild) 
           elD.removeChild(tglDesc);
        else
           elD.appendChild(tglDesc);
         setTimeout("toggleShowDesc()", 1000);
      }
  
      toggleShowDesc();
      toggleShowTitle();
  
      var elT2 = document.getElementById("title2");
      var tglTitle2 = elT2.firstChild;
      var elD2 = document.getElementById("desc2");
      var tglDesc2 = elD2.firstChild;
  
      function toggleShowTitle2() {
        if (tglTitle2.parentNode == elT2) 
           elT2.removeChild(tglTitle2);
        else
           elT2.appendChild(tglTitle2);
         setTimeout("toggleShowTitle2()", 1000);
      }
      function toggleShowDesc2() {
        if (tglDesc2.parentNode == elD2) 
           elD2.removeChild(tglDesc2);
        else
           elD2.appendChild(tglDesc2);
         setTimeout("toggleShowDesc2()", 1000);
      }
  
      toggleShowDesc2();
      toggleShowTitle2();
      </script>
  
      <g>
         <rect x="30"  y="75" width="75" height="75" style="fill:crimson"
               onclick="addChild(evt, 'desc')"/>
  
         <rect x="135" y="75" width="75" height="75" style="fill:gold"
               onclick="addChild(evt, 'title')"/>
  
         <rect x="240" y="75" width="75" height="75" style="fill:crimson"
               onclick="addChild(evt, 'desc')"
            ><title>Pre Existing Title</title></rect>
  
         <rect x="345" y="75" width="75" height="75" style="fill:gold"
               onclick="addChild(evt, 'title')"
            ><desc>Pre Existing Desc</desc></rect>
  
  
         <rect id="title" x="30" y="180" width="75" height="75" 
               style="fill:crimson"><title>Pre Existing Title</title></rect>
  
         <rect id="desc" x="135" y="180" width="75" height="75" 
               style="fill:gold"><desc>Pre-existing Desc</desc></rect>
  
         <rect id="title2" x="240" y="180" width="75" height="75" 
            style="fill:crimson"><title>Pre Existing Title</title>
                                 <desc>A constant Desc</desc></rect>
  
         <rect id="desc2" x="345" y="180" width="75" height="75" 
               style="fill:gold"><desc>Pre-existing Desc</desc>
                                 <title>A constant title</title></rect>
  
  
         <rect x="30" y="285" width="75" height="75" style="fill:crimson"
            ><title>Pre Existing Title</title
            ><desc id="foo">Text 2</desc></rect>
  
         <rect x="135" y="285" width="75" height="75" style="fill:gold"
            ><title id="bar">Title 1</title
            ><desc >Pre-existing Desc</desc></rect>
  
      </g>
  </svg>
  
  
  
  1.1                  xml-batik/samples/tests/spec/scripting/pathLength.svg
  
  Index: pathLength.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 2002  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 getPathLength, and getPointAtLength interfaces.                -->
  <!--                                                                        -->
  <!-- @author deweese@apache.org                                             -->
  <!-- @version $Id: pathLength.svg,v 1.1 2005/02/27 02:08:51 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="load(evt)"
       xmlns="http://www.w3.org/2000/svg" 
       xmlns:xlink="http://www.w3.org/1999/xlink">
  
     <title>Test getPathLength and getPointAtLength interfaces</title>
  
     <text x="50%" y="40" class="title"
      >Test getPathLength and getPointAtLength interfaces</text>
  
     <style type="text/css"><![CDATA[
       text { stroke: none }
       circle { stroke: none }
       path   { fill:none }
  ]]></style>
  
     <script type="text/ecmascript">
      var svgNamespaceURI = "http://www.w3.org/2000/svg";
      var doc;
  
      function doLength(cnt, dist) {
        var p = doc.getElementById("p"+cnt);
        var l = doc.getElementById("l"+cnt);
        var c = doc.getElementById("c"+cnt);
  
        var len, pt;
        len = p.getTotalLength();
        pt  = p.getPointAtLength(dist);
        l.appendChild(doc.createTextNode(("Len: " + len).substring(0, 10)));
        c.setAttribute("cx", ""+pt.getX());
        c.setAttribute("cy", ""+pt.getY());
      }
  
      function load(evt) {
        doc = evt.target.getOwnerDocument();
        doLength(1, 25);
        doLength(2, 25);
        doLength(3, 25);
        doLength(4, 25);
        doLength(5, 25);
        doLength(6, 25);
        doLength(7, (78.546)/2);
        doLength(8, 25);
  
      }
     </script>
  
     <g stroke="black">
        <path id="p1" d="M 20,60 h 50"/>  
        <text id="l1" x="80" y="65"/>
        <circle cx="45" cy="60" r="3" fill="red"/>
        <circle id="c1" cx="0" cy="0" r="1" fill="black"/>
  
        <path id="p2" d="M 20,60 l 40,30"/>
        <text id="l2" x="70" y="95"/>
        <circle cx="40" cy="75" r="3" fill="red"/>
        <circle id="c2" cx="0" cy="0" r="1" fill="black"/>
  
        <path id="p3" d="M 20,60 v 50"/>
        <text id="l3" x="30" y="115"/>
        <circle cx="20" cy="85" r="3" fill="red"/>
        <circle id="c3" cx="0" cy="0" r="1" fill="black"/>
  
        <path id="p4" d="M 170,60 c 15 0 35 0 50 0"/>
        <text id="l4" x="230" y="65"/>
        <circle cx="195" cy="60" r="3" fill="red"/>
        <circle id="c4" cx="0" cy="0" r="1" fill="black"/>
  
        <path id="p5" d="M 170,60 c 15 0 30 0 30,40"/>
        <text id="l5" x="210" y="105"/>
        <circle cx="192.8" cy="67.3" r="3" fill="red"/>
        <circle id="c5" cx="0" cy="0" r="1" fill="black"/>
  
        <path id="p6" d="M 20,170 a 10 0 0 0 0 50 0"/>
        <text id="l6" x="80" y="175"/>
        <circle cx="45" cy="170" r="3" fill="red"/>
        <circle id="c6" cx="0" cy="0" r="1" fill="black"/>
  
        <path id="p7" d="M 20,170 a 10 10 0 0 0 50 0"/>
        <text id="l7" x="80" y="195"/>
        <circle cx="45" cy="195" r="3" fill="red"/>
        <circle id="c7" cx="0" cy="0" r="1" fill="black"/>
  
        <path id="p8" d="M 170,170 v10h10v-10h10v10"/>
        <text id="l8" x="200" y="180"/>
        <circle cx="180" cy="175" r="3" fill="red"/>
        <circle id="c8" cx="0" cy="0" r="1" fill="black"/>
  
  
     </g>
  </svg>
  
  
  1.40      +9 -3      xml-batik/sources/org/apache/batik/bridge/AbstractGraphicsNodeBridge.java
  
  Index: AbstractGraphicsNodeBridge.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/bridge/AbstractGraphicsNodeBridge.java,v
  retrieving revision 1.39
  retrieving revision 1.40
  diff -u -r1.39 -r1.40
  --- AbstractGraphicsNodeBridge.java	30 Nov 2004 03:23:58 -0000	1.39
  +++ AbstractGraphicsNodeBridge.java	27 Feb 2005 02:08:51 -0000	1.40
  @@ -203,8 +203,14 @@
        * Invoked when an MutationEvent of type 'DOMNodeInserted' is fired.
        */
       public void handleDOMNodeInsertedEvent(MutationEvent evt) {
  -        // never called. The global listener on the document will
  -        // invoke this method on the parent element.
  +        if ( evt.getTarget() instanceof Element ){
  +            // Handle "generic" bridges.
  +            Element e2 = (Element)evt.getTarget();
  +            Bridge b = ctx.getBridge(e2);
  +            if (b instanceof GenericBridge) {
  +                ((GenericBridge) b).handleElement(ctx, e2);
  +            }
  +        }
       }
   
       /**
  
  
  
  1.81      +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.80
  retrieving revision 1.81
  diff -u -r1.80 -r1.81
  --- BridgeContext.java	15 Dec 2004 10:50:29 -0000	1.80
  +++ BridgeContext.java	27 Feb 2005 02:08:51 -0000	1.81
  @@ -58,6 +58,7 @@
   import org.apache.batik.util.ParsedURL;
   import org.apache.batik.util.SVGConstants;
   import org.apache.batik.util.Service;
  +
   import org.w3c.dom.Document;
   import org.w3c.dom.Element;
   import org.w3c.dom.Node;
  
  
  
  1.58      +3 -2      xml-batik/sources/org/apache/batik/bridge/BridgeEventSupport.java
  
  Index: BridgeEventSupport.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/bridge/BridgeEventSupport.java,v
  retrieving revision 1.57
  retrieving revision 1.58
  diff -u -r1.57 -r1.58
  --- BridgeEventSupport.java	22 Feb 2005 09:12:57 -0000	1.57
  +++ BridgeEventSupport.java	27 Feb 2005 02:08:51 -0000	1.58
  @@ -93,7 +93,8 @@
           public void handleEvent(Event evt) {
               dispatcher.removeGraphicsNodeMouseListener(listener);
               dispatcher.removeGraphicsNodeKeyListener(listener);
  -            evt.getTarget().removeEventListener("SVGUnload", this, false);
  +            evt.getTarget().removeEventListener
  +                (SVGConstants.SVG_SVGUNLOAD_EVENT_TYPE, this, false);
           }
       }
   
  
  
  
  1.4       +6 -13     xml-batik/sources/org/apache/batik/bridge/SVGDescElementBridge.java
  
  Index: SVGDescElementBridge.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/bridge/SVGDescElementBridge.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- SVGDescElementBridge.java	18 Aug 2004 07:12:33 -0000	1.3
  +++ SVGDescElementBridge.java	27 Feb 2005 02:08:51 -0000	1.4
  @@ -1,6 +1,6 @@
   /*
   
  -   Copyright 2001  The Apache Software Foundation 
  +   Copyright 2001,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.
  @@ -25,7 +25,7 @@
    * @author <a href="mailto:vhardy@apache.org">Vincent Hardy</a>
    * @version $Id$
    */
  -public class SVGDescElementBridge extends AbstractSVGBridge implements GenericBridge {
  +public class SVGDescElementBridge extends SVGDescriptiveElementBridge {
   
       /**
        * Constructs a new bridge for the &lt;desc&gt; element.
  @@ -39,17 +39,10 @@
           return SVG_DESC_TAG;
       }
   
  +
       /**
  -     * Invoked to handle an <tt>Element</tt> for a given <tt>BridgeContext</tt>.
  -     * For example, see the <tt>SVGDescElementBridge</tt>.
  -     *
  -     * @param ctx the bridge context to use
  -     * @param e the element that describes the graphics node to build
  +     * Returns a new instance of this bridge.
        */
  -    public void handleElement(BridgeContext ctx, Element e){
  -        UserAgent ua = ctx.getUserAgent();
  -        ua.handleElement(e, null);
  -    }
  -
  +    public Bridge getInstance() { return new SVGDescElementBridge(); }
   }
   
  
  
  
  1.7       +57 -41    xml-batik/sources/org/apache/batik/bridge/SVGKernElementBridge.java
  
  Index: SVGKernElementBridge.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/bridge/SVGKernElementBridge.java,v
  retrieving revision 1.6
  retrieving revision 1.7
  diff -u -r1.6 -r1.7
  --- SVGKernElementBridge.java	1 Sep 2004 09:35:22 -0000	1.6
  +++ SVGKernElementBridge.java	27 Feb 2005 02:08:51 -0000	1.7
  @@ -75,19 +75,23 @@
                   firstUnicodeRanges.add(new UnicodeRange(token));
               } else {
                   int[] glyphCodes = font.getGlyphCodesForUnicode(token);
  -                if (firstGlyphSet == null)
  +                if (firstGlyphSet == null) {
                       firstGlyphSet = glyphCodes;
  -                else if ((firstGlyphLen + glyphCodes.length) > 
  -                         firstGlyphSet.length) {
  -                    int sz = firstGlyphSet.length*2;
  -                    if (sz <firstGlyphLen + glyphCodes.length)
  -                        sz = firstGlyphLen + glyphCodes.length;
  -                    int [] tmp = new int[sz];
  +                    firstGlyphLen = glyphCodes.length;
  +                }else {
  +                    if ((firstGlyphLen + glyphCodes.length) > 
  +                        firstGlyphSet.length) {
  +                        int sz = firstGlyphSet.length*2;
  +                        if (sz <firstGlyphLen + glyphCodes.length)
  +                            sz = firstGlyphLen + glyphCodes.length;
  +                        int [] tmp = new int[sz];
  +                        for (int i = 0; i < firstGlyphLen; i++)
  +                            tmp[i] = firstGlyphSet[i];
  +                        firstGlyphSet = tmp;
  +                    }
                       for (int i = 0; i < glyphCodes.length; i++)
  -                        tmp[i] = firstGlyphSet[i];
  +                        firstGlyphSet[firstGlyphLen++] = glyphCodes[i];
                   }
  -                for (int i = 0; i < glyphCodes.length; i++)
  -                    firstGlyphSet[firstGlyphLen++] = glyphCodes[i];
               }
           }
           
  @@ -99,19 +103,23 @@
                   secondUnicodeRanges.add(new UnicodeRange(token));
               } else {
                   int[] glyphCodes = font.getGlyphCodesForUnicode(token);
  -                if (secondGlyphSet == null)
  +                if (secondGlyphSet == null) {
                       secondGlyphSet = glyphCodes;
  -                else if ((secondGlyphLen + glyphCodes.length) > 
  -                         secondGlyphSet.length) {
  -                    int sz = secondGlyphSet.length*2;
  -                    if (sz <secondGlyphLen + glyphCodes.length)
  -                        sz = secondGlyphLen + glyphCodes.length;
  -                    int [] tmp = new int[sz];
  +                    secondGlyphLen = glyphCodes.length;
  +                } else {
  +                    if ((secondGlyphLen + glyphCodes.length) > 
  +                        secondGlyphSet.length) {
  +                        int sz = secondGlyphSet.length*2;
  +                        if (sz <secondGlyphLen + glyphCodes.length)
  +                            sz = secondGlyphLen + glyphCodes.length;
  +                        int [] tmp = new int[sz];
  +                        for (int i = 0; i < secondGlyphLen; i++)
  +                            tmp[i] = secondGlyphSet[i];
  +                        secondGlyphSet = tmp;
  +                    }
                       for (int i = 0; i < glyphCodes.length; i++)
  -                        tmp[i] = secondGlyphSet[i];
  +                        secondGlyphSet[secondGlyphLen++] = glyphCodes[i];
                   }
  -                for (int i = 0; i < glyphCodes.length; i++)
  -                    secondGlyphSet[secondGlyphLen++] = glyphCodes[i];
               }
           }
           
  @@ -120,19 +128,23 @@
           while (st.hasMoreTokens()) {
               String token = st.nextToken();
               int[] glyphCodes = font.getGlyphCodesForName(token);
  -            if (firstGlyphSet == null)
  +            if (firstGlyphSet == null) {
                   firstGlyphSet = glyphCodes;
  -            else if ((firstGlyphLen + glyphCodes.length) > 
  -                     firstGlyphSet.length) {
  -                int sz = firstGlyphSet.length*2;
  -                if (sz <firstGlyphLen + glyphCodes.length)
  -                    sz = firstGlyphLen + glyphCodes.length;
  -                int [] tmp = new int[sz];
  +                firstGlyphLen = glyphCodes.length;
  +            }else {
  +                if ((firstGlyphLen + glyphCodes.length) > 
  +                    firstGlyphSet.length) {
  +                    int sz = firstGlyphSet.length*2;
  +                    if (sz <firstGlyphLen + glyphCodes.length)
  +                        sz = firstGlyphLen + glyphCodes.length;
  +                    int [] tmp = new int[sz];
  +                    for (int i = 0; i < firstGlyphLen; i++)
  +                        tmp[i] = firstGlyphSet[i];
  +                    firstGlyphSet = tmp;
  +                }
                   for (int i = 0; i < glyphCodes.length; i++)
  -                    tmp[i] = firstGlyphSet[i];
  +                    firstGlyphSet[firstGlyphLen++] = glyphCodes[i];
               }
  -            for (int i = 0; i < glyphCodes.length; i++)
  -                firstGlyphSet[firstGlyphLen++] = glyphCodes[i];
           }
           
           // process the g2 attribute
  @@ -140,19 +152,23 @@
           while (st.hasMoreTokens()) {
               String token = st.nextToken();
               int[] glyphCodes = font.getGlyphCodesForName(token);
  -            if (secondGlyphSet == null)
  +            if (secondGlyphSet == null) {
                   secondGlyphSet = glyphCodes;
  -            else if ((secondGlyphLen + glyphCodes.length) > 
  -                     secondGlyphSet.length) {
  -                int sz = secondGlyphSet.length*2;
  -                if (sz <secondGlyphLen + glyphCodes.length)
  -                    sz = secondGlyphLen + glyphCodes.length;
  -                int [] tmp = new int[sz];
  +                secondGlyphLen = glyphCodes.length;
  +            } else {
  +                if ((secondGlyphLen + glyphCodes.length) > 
  +                    secondGlyphSet.length) {
  +                    int sz = secondGlyphSet.length*2;
  +                    if (sz <secondGlyphLen + glyphCodes.length)
  +                        sz = secondGlyphLen + glyphCodes.length;
  +                    int [] tmp = new int[sz];
  +                    for (int i = 0; i < secondGlyphLen; i++)
  +                        tmp[i] = secondGlyphSet[i];
  +                    secondGlyphSet = tmp;
  +                }
                   for (int i = 0; i < glyphCodes.length; i++)
  -                    tmp[i] = secondGlyphSet[i];
  +                    secondGlyphSet[secondGlyphLen++] = glyphCodes[i];
               }
  -            for (int i = 0; i < glyphCodes.length; i++)
  -                secondGlyphSet[secondGlyphLen++] = glyphCodes[i];
           }
   
           // construct the arrays
  
  
  
  1.20      +30 -2     xml-batik/sources/org/apache/batik/bridge/SVGPathElementBridge.java
  
  Index: SVGPathElementBridge.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/bridge/SVGPathElementBridge.java,v
  retrieving revision 1.19
  retrieving revision 1.20
  diff -u -r1.19 -r1.20
  --- SVGPathElementBridge.java	18 Aug 2004 07:12:35 -0000	1.19
  +++ SVGPathElementBridge.java	27 Feb 2005 02:08:51 -0000	1.20
  @@ -19,13 +19,17 @@
   
   import java.awt.Shape;
   import java.awt.geom.GeneralPath;
  +import java.awt.geom.Point2D;
   
   import org.apache.batik.css.engine.CSSEngineEvent;
   import org.apache.batik.css.engine.SVGCSSEngine;
  +import org.apache.batik.dom.svg.SVGPathContext;
  +import org.apache.batik.ext.awt.geom.PathLength;
   import org.apache.batik.gvt.ShapeNode;
   import org.apache.batik.parser.AWTPathProducer;
   import org.apache.batik.parser.ParseException;
   import org.apache.batik.parser.PathParser;
  +
   import org.w3c.dom.Element;
   import org.w3c.dom.events.MutationEvent;
   
  @@ -35,7 +39,8 @@
    * @author <a href="mailto:tkormann@apache.org">Thierry Kormann</a>
    * @version $Id$
    */
  -public class SVGPathElementBridge extends SVGDecoratedShapeElementBridge {
  +public class SVGPathElementBridge extends SVGDecoratedShapeElementBridge 
  +       implements SVGPathContext {
   
       /**
        * default shape for the update of 'd' when
  @@ -124,4 +129,27 @@
               super.handleCSSPropertyChanged(property);
           }
       }
  +
  +    Shape      pathLengthShape = null;
  +    PathLength pathLength      = null;
  +
  +    PathLength getPathLengthObj() {
  +        Shape s = ((ShapeNode)node).getShape();
  +        if (pathLengthShape != s) {
  +            pathLength = new PathLength(s);
  +            pathLengthShape = s;
  +        }
  +        return pathLength;
  +    }
  +
  +    // SVGPathContext interface
  +    public float getTotalLength() {
  +        PathLength pl = getPathLengthObj();
  +        return pl.lengthOfPath();
  +    }
  +
  +    public Point2D getPointAtLength(float distance) {
  +        PathLength pl = getPathLengthObj();
  +        return pl.pointAtLength(distance);
  +    }
   }
  
  
  
  1.4       +5 -13     xml-batik/sources/org/apache/batik/bridge/SVGTitleElementBridge.java
  
  Index: SVGTitleElementBridge.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/bridge/SVGTitleElementBridge.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- SVGTitleElementBridge.java	18 Aug 2004 07:12:36 -0000	1.3
  +++ SVGTitleElementBridge.java	27 Feb 2005 02:08:51 -0000	1.4
  @@ -1,6 +1,6 @@
   /*
   
  -   Copyright 2001  The Apache Software Foundation 
  +   Copyright 2001,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.
  @@ -26,7 +26,7 @@
    * @author <a href="mailto:tkormann@apache.org">Thierry Kormann</a>
    * @version $Id$
    */
  -public class SVGTitleElementBridge extends AbstractSVGBridge implements GenericBridge {
  +public class SVGTitleElementBridge extends SVGDescriptiveElementBridge {
   
       /**
        * Constructs a new bridge for the &lt;title&gt; element.
  @@ -41,16 +41,8 @@
       }
   
       /**
  -     * Invoked to handle an <tt>Element</tt> for a given <tt>BridgeContext</tt>.
  -     * For example, see the <tt>SVGTitleElementBridge</tt>.
  -     *
  -     * @param ctx the bridge context to use
  -     * @param e the element that describes the graphics node to build
  +     * Returns a new instance of this bridge.
        */
  -    public void handleElement(BridgeContext ctx, Element e){
  -        UserAgent ua = ctx.getUserAgent();
  -        ua.handleElement(e, null);
  -    }
  -
  +    public Bridge getInstance() { return new SVGTitleElementBridge(); }
   }
   
  
  
  
  1.1                  xml-batik/sources/org/apache/batik/bridge/SVGDescriptiveElementBridge.java
  
  Index: SVGDescriptiveElementBridge.java
  ===================================================================
  /*
  
     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.
  
  */
  
  package org.apache.batik.bridge;
  
  import java.awt.geom.AffineTransform;
  import java.awt.geom.Rectangle2D;
  
  import org.w3c.dom.Element;
  import org.w3c.dom.events.MutationEvent;
  
  import org.apache.batik.css.engine.CSSEngineEvent;
  import org.apache.batik.dom.svg.SVGContext;
  import org.apache.batik.dom.svg.SVGOMElement;
  
  /**
   * Base class for 'descriptive' elements, mostly title and desc.
   *
   * @author <a href="mailto:deweese@apache.org>deweese</a>
   * @version $Id: SVGDescriptiveElementBridge.java,v 1.1 2005/02/27 02:08:51 deweese Exp $
   */
  public abstract class SVGDescriptiveElementBridge extends AbstractSVGBridge 
      implements GenericBridge,  BridgeUpdateHandler, SVGContext {
  
      Element theElt;
      Element parent;
      BridgeContext theCtx;
  
      public SVGDescriptiveElementBridge() {
      }
  
  
      /**
       * Invoked to handle an <tt>Element</tt> for a given
       * <tt>BridgeContext</tt>.  For example, see the
       * <tt>SVGDescElementBridge</tt>.
       *
       * @param ctx the bridge context to use
       * @param e the element that describes the graphics node to build
       */
      public void handleElement(BridgeContext ctx, Element e){
          UserAgent ua = ctx.getUserAgent();
          ua.handleElement(e, Boolean.TRUE);
          
          if (ctx.isDynamic()) {
              SVGDescriptiveElementBridge b;
              b = (SVGDescriptiveElementBridge)getInstance();
              b.theElt = e;
              b.parent = (Element)e.getParentNode();
              b.theCtx = ctx;
              ((SVGOMElement)e).setSVGContext(b);
          }
  
      }
  
      // BridgeUpdateHandler implementation ////////////////////////////////////
  
      public void dispose() {
          UserAgent ua = theCtx.getUserAgent();
          ((SVGOMElement)theElt).setSVGContext(null);
          ua.handleElement(theElt, parent);
          theElt = null;
          parent = null;
      }
      public void handleDOMNodeInsertedEvent(MutationEvent evt) { 
          UserAgent ua = theCtx.getUserAgent();
          ua.handleElement(theElt, Boolean.TRUE);
      }
      public void handleDOMCharacterDataModified(MutationEvent evt) { 
          UserAgent ua = theCtx.getUserAgent();
          ua.handleElement(theElt, Boolean.TRUE);
      }
  
      public void handleDOMNodeRemovedEvent (MutationEvent evt) { 
          dispose();
      }
  
      public void handleDOMAttrModifiedEvent(MutationEvent evt) { }
      public void handleCSSEngineEvent(CSSEngineEvent evt) { }
  
      // SVGContext implementation ///////////////////////////////////////////
  
      /**
       * Returns the size of a px CSS unit in millimeters.
       */
      public float getPixelUnitToMillimeter() {
          return theCtx.getUserAgent().getPixelUnitToMillimeter();
      }
  
      /**
       * Returns the size of a px CSS unit in millimeters.
       * This will be removed after next release.
       * @see #getPixelUnitToMillimeter()
       */
      public float getPixelToMM() {
          return getPixelUnitToMillimeter();
              
      }
  
      public Rectangle2D getBBox() { return null; }
      public AffineTransform getScreenTransform() { 
          return theCtx.getUserAgent().getTransform();
      }
      public void setScreenTransform(AffineTransform at) { 
          theCtx.getUserAgent().setTransform(at);
      }
      public AffineTransform getCTM() { return null; }
      public AffineTransform getGlobalTransform() { return null; }
      public float getViewportWidth() {
          return theCtx.getBlockWidth(theElt);
      }
      public float getViewportHeight() {
          return theCtx.getBlockHeight(theElt);
      }
      public float getFontSize() { return 0; }
  };
  
  
  
  1.11      +4 -7      xml-batik/sources/org/apache/batik/dom/svg/SVGLocatableSupport.java
  
  Index: SVGLocatableSupport.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/dom/svg/SVGLocatableSupport.java,v
  retrieving revision 1.10
  retrieving revision 1.11
  diff -u -r1.10 -r1.11
  --- SVGLocatableSupport.java	30 Nov 2004 03:23:58 -0000	1.10
  +++ SVGLocatableSupport.java	27 Feb 2005 02:08:51 -0000	1.11
  @@ -66,8 +66,7 @@
       }
   
       /**
  -     * To implement {@link
  -     * org.w3c.dom.svg.SVGLocatable#getBBox()}.
  +     * To implement {@link org.w3c.dom.svg.SVGLocatable#getBBox()}.
        */
       public static SVGRect getBBox(Element elt) {
           final SVGOMElement svgelt = (SVGOMElement)elt;
  @@ -112,8 +111,7 @@
       }
   
       /**
  -     * To implement {@link
  -     * org.w3c.dom.svg.SVGLocatable#getCTM()}.
  +     * To implement {@link org.w3c.dom.svg.SVGLocatable#getCTM()}.
        */
       public static SVGMatrix getCTM(Element elt) {
           final SVGOMElement svgelt = (SVGOMElement)elt;
  @@ -125,8 +123,7 @@
       }
   
       /**
  -     * To implement {@link
  -     * org.w3c.dom.svg.SVGLocatable#getScreenCTM()}.
  +     * To implement {@link org.w3c.dom.svg.SVGLocatable#getScreenCTM()}.
        */
       public static SVGMatrix getScreenCTM(Element elt) {
           final SVGOMElement svgelt  = (SVGOMElement)elt;
  
  
  
  1.10      +8 -11     xml-batik/sources/org/apache/batik/dom/svg/SVGOMPathElement.java
  
  Index: SVGOMPathElement.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/dom/svg/SVGOMPathElement.java,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- SVGOMPathElement.java	18 Aug 2004 07:13:17 -0000	1.9
  +++ SVGOMPathElement.java	27 Feb 2005 02:08:51 -0000	1.10
  @@ -81,35 +81,35 @@
        * <b>DOM</b>: Implements {@link SVGPathElement#getPathLength()}.
        */
       public SVGAnimatedNumber getPathLength() {
  -        throw new RuntimeException(" !!! getPathLength()");
  +        throw new RuntimeException(" !!! getPathLength() Not Yet Implemented");
       }
   
       /**
        * <b>DOM</b>: Implements {@link SVGPathElement#getTotalLength()}.
        */
       public float getTotalLength() {
  -        throw new RuntimeException(" !!! getTotalLength()");
  +        return SVGPathSupport.getTotalLength(this);
       }
   
       /**
        * <b>DOM</b>: Implements {@link SVGPathElement#getPointAtLength(float)}.
        */
       public SVGPoint getPointAtLength(float distance) {
  -        throw new RuntimeException(" !!! getPointAtLength()");
  +        return SVGPathSupport.getPointAtLength(this, distance);
       }
   
       /**
        * <b>DOM</b>: Implements {@link SVGPathElement#getPathSegAtLength(float)}.
        */
       public int getPathSegAtLength(float distance) {
  -        throw new RuntimeException(" !!! getPathSegAtLength()");
  +        throw new RuntimeException
  +            (" !!! getPathSegAtLength() Not Yet Implemented");
       }
   
       /**
        * <b>DOM</b>: Implements {@link SVGPathElement#getPathSegList()}.
        */
       public SVGPathSegList getPathSegList() {
  -        //throw new RuntimeException(" !!! getPathSegList()");
           return SVGAnimatedPathDataSupport.getPathSegList(this);
       }
   
  @@ -117,7 +117,6 @@
        * <b>DOM</b>: Implements {@link SVGPathElement#getNormalizedPathSegList()}.
        */
       public SVGPathSegList getNormalizedPathSegList() {
  -        //throw new RuntimeException(" !!! getNormalizedPathSegList()");
           return SVGAnimatedPathDataSupport.getNormalizedPathSegList(this);
       }
   
  @@ -125,7 +124,6 @@
        * <b>DOM</b>: Implements {@link SVGPathElement#getAnimatedPathSegList()}.
        */
       public SVGPathSegList getAnimatedPathSegList() {
  -        //throw new RuntimeException(" !!! getAnimatedPathSegList()");
           return SVGAnimatedPathDataSupport.getAnimatedNormalizedPathSegList(this);
       }
   
  @@ -133,8 +131,8 @@
        * <b>DOM</b>: Implements {@link SVGPathElement#getAnimatedNormalizedPathSegList()}.
        */
       public SVGPathSegList getAnimatedNormalizedPathSegList() {
  -        //throw new RuntimeException(" !!! getAnimatedNormalizedPathSegList()");
  -        return SVGAnimatedPathDataSupport.getAnimatedNormalizedPathSegList(this);
  +        return SVGAnimatedPathDataSupport.getAnimatedNormalizedPathSegList
  +            (this);
       }
   
       // Factory methods /////////////////////////////////////////////////////
  @@ -143,7 +141,6 @@
        * <b>DOM</b>: Implements {@link SVGPathElement#createSVGPathSegClosePath()}.
        */
       public SVGPathSegClosePath createSVGPathSegClosePath() {
  -        //throw new RuntimeException(" !!! createSVGPathSegClosePath()");
           return new SVGPathSegClosePath(){
                   public short getPathSegType(){
                       return SVGPathSeg.PATHSEG_CLOSEPATH;
  
  
  
  1.1                  xml-batik/sources/org/apache/batik/dom/svg/SVGPathContext.java
  
  Index: SVGPathContext.java
  ===================================================================
  /*
  
     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.
  
  */
  
  package org.apache.batik.dom.svg;
  
  import java.awt.geom.Point2D;
  
  /**
   * Context class for the SVG path element to support extra
   * methods.
   *
   * @author <a href="mailto:deweese@apache.org>deweese</a>
   * @version $Id: SVGPathContext.java,v 1.1 2005/02/27 02:08:51 deweese Exp $
   */
  public interface SVGPathContext extends SVGContext {
  
      public float getTotalLength();
  
      public Point2D getPointAtLength(float distance);
  };
  
  
  
  1.1                  xml-batik/sources/org/apache/batik/dom/svg/SVGPathSupport.java
  
  Index: SVGPathSupport.java
  ===================================================================
  /*
  
     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.
  
  */
  
  package org.apache.batik.dom.svg;
  
  import java.awt.geom.Point2D;
  
  import org.w3c.dom.svg.SVGPoint;
  import org.w3c.dom.svg.SVGMatrix;
  import org.w3c.dom.DOMException;
  
  /**
   * The clas provides support for the SVGPath interface.
   *
   * @author <a href="mailto:deweese@apache.org>deweese</a>
   * @version $Id: SVGPathSupport.java,v 1.1 2005/02/27 02:08:51 deweese Exp $
   */
  public class SVGPathSupport {
  
      /**
       * To implement {@link org.w3c.dom.svg.SVGPath#getTotalLength()}.
       */
      public static float getTotalLength(SVGOMPathElement path) {
          SVGPathContext pathCtx = (SVGPathContext)path.getSVGContext();
          return pathCtx.getTotalLength();
      }
  
  
      /**
       * To implement {@link org.w3c.dom.svg.SVGPath#getPointAtLength()}.
       */
      public static SVGPoint getPointAtLength(final SVGOMPathElement path,
                                              final float distance) {
          final SVGPathContext pathCtx = (SVGPathContext)path.getSVGContext();
          if (pathCtx == null) return null;
  
          return new SVGPoint() {
                  public float getX() {
                      Point2D pt = pathCtx.getPointAtLength(distance);
                      return (float)pt.getX();
                  }
                  public float getY() {
                      Point2D pt = pathCtx.getPointAtLength(distance);
                      return (float)pt.getY();
                  }
                  public void setX(float x) throws DOMException {
                      throw path.createDOMException
                          (DOMException.NO_MODIFICATION_ALLOWED_ERR,
                           "readonly.point", null);
                  }
                  public void setY(float y) throws DOMException {
                      throw path.createDOMException
                          (DOMException.NO_MODIFICATION_ALLOWED_ERR,
                           "readonly.point", null);
                  }
                  public SVGPoint matrixTransform ( SVGMatrix matrix ) {
                      throw path.createDOMException
                          (DOMException.NO_MODIFICATION_ALLOWED_ERR,
                           "readonly.point", null);
                  }
              };
      }
  };
  
  
  
  1.2       +1 -3      xml-batik/sources/org/apache/batik/ext/awt/geom/Linear.java
  
  Index: Linear.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/ext/awt/geom/Linear.java,v
  retrieving revision 1.1
  retrieving revision 1.2
  diff -u -r1.1 -r1.2
  --- Linear.java	18 Nov 2004 01:46:58 -0000	1.1
  +++ Linear.java	27 Feb 2005 02:08:52 -0000	1.2
  @@ -199,9 +199,7 @@
           return Math.sqrt(dx*dx+dy*dy);
       }
       public double getLength(double maxErr) {
  -        double dx = p2.x-p1.x;
  -        double dy = p2.y-p1.y;
  -        return Math.sqrt(dx*dx+dy*dy);
  +        return getLength();
       }
   
       public String toString() { 
  
  
  
  1.8       +2 -2      xml-batik/sources/org/apache/batik/ext/awt/geom/PathLength.java
  
  Index: PathLength.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/ext/awt/geom/PathLength.java,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- PathLength.java	18 Nov 2004 01:46:58 -0000	1.7
  +++ PathLength.java	27 Feb 2005 02:08:52 -0000	1.8
  @@ -250,7 +250,7 @@
   
       }
   
  -    private int findUpperIndex(float length) {
  +    public int findUpperIndex(float length) {
           if (!initialised)
               initialise();
   
  
  
  
  1.18      +10 -1     xml-batik/sources/org/apache/batik/gvt/renderer/BasicTextPainter.java
  
  Index: BasicTextPainter.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/gvt/renderer/BasicTextPainter.java,v
  retrieving revision 1.17
  retrieving revision 1.18
  diff -u -r1.17 -r1.18
  --- BasicTextPainter.java	18 Aug 2004 07:14:38 -0000	1.17
  +++ BasicTextPainter.java	27 Feb 2005 02:08:52 -0000	1.18
  @@ -123,6 +123,15 @@
           public TextNode getTextNode() {
               return node;
           }
  +
  +    /**
  +     * Returns the index of the character that has been hit.
  +     *
  +     * @return The character index.
  +     */
  +        public int getCharIndex() { 
  +            return hit.getCharIndex(); 
  +        }
       }
   }
   
  
  
  
  1.5       +9 -2      xml-batik/sources/org/apache/batik/gvt/text/Mark.java
  
  Index: Mark.java
  ===================================================================
  RCS file: /home/cvs/xml-batik/sources/org/apache/batik/gvt/text/Mark.java,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- Mark.java	18 Aug 2004 07:14:42 -0000	1.4
  +++ Mark.java	27 Feb 2005 02:08:52 -0000	1.5
  @@ -29,5 +29,12 @@
       /*
        * Return the TextNode this Mark is associated with 
        */
  -    TextNode getTextNode();
  +    public TextNode getTextNode();
  +
  +    /**
  +     * Returns the index of the character that has been hit.
  +     *
  +     * @return The character index.
  +     */
  +    public int getCharIndex();
   }
  
  
  
  1.51      +253 -131  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.50
  retrieving revision 1.51
  diff -u -r1.50 -r1.51
  --- JSVGCanvas.java	22 Feb 2005 09:13:03 -0000	1.50
  +++ JSVGCanvas.java	27 Feb 2005 02:08:52 -0000	1.51
  @@ -28,7 +28,10 @@
   import java.awt.geom.AffineTransform;
   import java.beans.PropertyChangeListener;
   import java.beans.PropertyChangeSupport;
  +import java.util.Iterator;
   import java.util.List;
  +import java.util.Map;
  +import java.util.WeakHashMap;
   
   import javax.swing.AbstractAction;
   import javax.swing.ActionMap;
  @@ -52,6 +55,7 @@
   import org.apache.batik.util.SVGConstants;
   import org.apache.batik.util.XMLConstants;
   import org.apache.batik.util.gui.JErrorPane;
  +
   import org.w3c.dom.Element;
   import org.w3c.dom.Node;
   import org.w3c.dom.events.Event;
  @@ -173,13 +177,33 @@
        * Keeps track of the last known mouse position over the canvas.
        * This is used for displaying tooltips at the right location.
        */
  -    protected LocationListener locationListener = null;
  +    protected LocationListener locationListener = new LocationListener();
  +
  +    /**
  +     * Mapping of elements to listeners so they can be removed,
  +     * if the tooltip is removed.
  +     */
  +    protected Map toolTipMap = null;
  +    protected EventListener toolTipListener = new ToolTipModifier();
  +    protected EventTarget   lastTarget = null;;
  +    /**
  +     * The time of the last tool tip event.
  +     */
  +    protected long lastToolTipEventTimeStamp;
  +
  +    /**
  +     * The target for which the last tool tip event was fired.
  +     */
  +    protected EventTarget lastToolTipEventTarget;
  +
  +
   
       /**
        * Creates a new JSVGCanvas.
        */
       public JSVGCanvas() {
           this(null, true, true);
  +        addMouseMotionListener(locationListener);
       }
   
       /**
  @@ -217,6 +241,7 @@
   
               installKeyboardActions();
           }
  +        addMouseMotionListener(locationListener);
       }
   
       /**
  @@ -520,6 +545,35 @@
   
       }
   
  +    protected void installSVGDocument(SVGDocument doc) {
  +        if (svgDocument != null) {
  +            EventTarget root;
  +            root = (EventTarget)svgDocument.getRootElement();
  +            root.removeEventListener(SVGConstants.SVG_EVENT_MOUSEOVER,
  +                                     toolTipListener, false);
  +            root.removeEventListener(SVGConstants.SVG_EVENT_MOUSEOUT,
  +                                     toolTipListener, false);
  +            lastTarget = null;
  +        }
  +
  +        if (toolTipMap != null) {
  +            toolTipMap.clear();
  +        }
  +
  +        if (doc != null) {
  +            EventTarget root;
  +            root = (EventTarget)doc.getRootElement();
  +            // On mouseover, it sets the tooltip to the given value
  +            root.addEventListener(SVGConstants.SVG_EVENT_MOUSEOVER,
  +                                  toolTipListener, false);
  +            // On mouseout, it removes the tooltip
  +            root.addEventListener(SVGConstants.SVG_EVENT_MOUSEOUT,
  +                                  toolTipListener, false);
  +        }
  +
  +        super.installSVGDocument(doc);
  +    }
  +
       // ----------------------------------------------------------------------
       // Actions
       // ----------------------------------------------------------------------
  @@ -749,16 +803,6 @@
               = "JSVGCanvas.CanvasUserAgent.ToolTip.titleAndDesc";
   
           /**
  -         * The time of the last tool tip event.
  -         */
  -        protected long lastToolTipEventTimeStamp;
  -
  -        /**
  -         * The target for which the last tool tip event was fired.
  -         */
  -        protected EventTarget lastToolTipEventTarget;
  -
  -        /**
            * The handleElement method builds a tool tip from the
            * content of a &lt;title&gt; element, a &lt;desc&gt;
            * element or both. <br/>
  @@ -787,65 +831,103 @@
   
               // Don't handle tool tips for the root SVG element.
               if (elt.getParentNode() == 
  -                    elt.getOwnerDocument().getDocumentElement()) {
  +                elt.getOwnerDocument().getDocumentElement()) {
                   return;
               }
   
  +            Element parent;
  +            // When node is removed data is old parent node
  +            // since we can't get it otherwise.
  +            if (data instanceof Element) parent = (Element)data;
  +            else                         parent = (Element)elt.getParentNode();
  +
  +            Element descPeer = null;
  +            Element titlePeer = null;
               if (elt.getLocalName().equals(SVGConstants.SVG_TITLE_TAG)) {
  -                // If there is a <desc> peer, do nothing as the tooltip will
  -                // be handled when handleElement is invoked for the <desc>
  -                // peer.
  -                if (hasPeerWithTag
  -                    (elt,
  -                     SVGConstants.SVG_NAMESPACE_URI,
  -                     SVGConstants.SVG_DESC_TAG)){
  -                    return;
  -                }
  -                
  -                elt.normalize();
  -                if (elt.getFirstChild() == null) {
  -                    return;
  -                }
  -                String toolTip = elt.getFirstChild().getNodeValue();
  -                if (toolTip == null || toolTip.length() == 0) {
  -                    return;
  +                if (data == Boolean.TRUE) 
  +                    titlePeer = elt;
  +                descPeer = getPeerWithTag(parent,
  +                                           SVGConstants.SVG_NAMESPACE_URI,
  +                                           SVGConstants.SVG_DESC_TAG);
  +            } else if (elt.getLocalName().equals(SVGConstants.SVG_DESC_TAG)) {
  +                if (data == Boolean.TRUE) 
  +                    descPeer = elt;
  +                titlePeer = getPeerWithTag(parent,
  +                                           SVGConstants.SVG_NAMESPACE_URI,
  +                                           SVGConstants.SVG_TITLE_TAG);
  +            }
  +
  +            String titleTip = null;
  +            if (titlePeer != null) {
  +                titlePeer.normalize();
  +                if (titlePeer.getFirstChild() != null)
  +                    titleTip = titlePeer.getFirstChild().getNodeValue();
  +            }
  +
  +            String descTip = null;
  +            if (descPeer != null) {
  +                descPeer.normalize();
  +                if (descPeer.getFirstChild() != null)
  +                    descTip = descPeer.getFirstChild().getNodeValue();
  +            }
  +
  +            final String toolTip;
  +            if ((titleTip != null) && (titleTip.length() != 0)) {
  +                if ((descTip != null) && (descTip.length() != 0)) {
  +                    toolTip = Messages.formatMessage
  +                        (TOOLTIP_TITLE_AND_TEXT,
  +                         new Object[] { toFormattedHTML(titleTip),
  +                                        toFormattedHTML(descTip)});
  +                } else {
  +                    toolTip = Messages.formatMessage
  +                        (TOOLTIP_TITLE_ONLY,
  +                         new Object[]{toFormattedHTML(titleTip)});
                   }
  -                toolTip = Messages.formatMessage
  -                    (TOOLTIP_TITLE_ONLY,
  -                     new Object[]{toFormattedHTML(toolTip)});
  -                
  -                setToolTip((Element)(elt.getParentNode()), toolTip);
  -            } else if (elt.getLocalName().equals
  -                       (SVGConstants.SVG_DESC_TAG)) {
  -                //  If there is a <title> peer, prepend its content to the
  -                // content of the <desc> element.
  -                elt.normalize();
  -                if (elt.getFirstChild() == null) {
  -                    return;
  +            } else {
  +                if ((descTip != null) && (descTip.length() != 0)) {
  +                    toolTip = Messages.formatMessage
  +                        (TOOLTIP_DESC_ONLY,
  +                         new Object[]{toFormattedHTML(descTip)});
  +                } else {
  +                    toolTip = null;
                   }
  -                String toolTip = elt.getFirstChild().getNodeValue();
  -                if (toolTip == null || toolTip.length() == 0) {
  -                    return;
  +            }
  +
  +            if (toolTip == null) {
  +                removeToolTip(parent);
  +                return;
  +            }
  +
  +            if (lastTarget != parent) {
  +                setToolTip(parent, toolTip);
  +            } else {
  +                // Already has focus check if it already has tip text.
  +                Object o = null;
  +                if (toolTipMap != null) {
  +                    o = toolTipMap.get(parent);
  +                    toolTipMap.put(parent, toolTip);
                   }
  -                
  -                Element titlePeer =
  -                    getPeerWithTag(elt,
  -                                   SVGConstants.SVG_NAMESPACE_URI,
  -                                   SVGConstants.SVG_TITLE_TAG);
  -                if (titlePeer != null) {
  -                    titlePeer.normalize();
  -                    toolTip = Messages.formatMessage(TOOLTIP_TITLE_AND_TEXT,
  -                                                     new Object[] {
  -                                                         toFormattedHTML(titlePeer.getFirstChild().getNodeValue()),
  -                                                         toFormattedHTML(toolTip)});
  +
  +                if (o != null) {
  +                    // Update components tooltip text now.
  +                    EventQueue.invokeLater(new Runnable() {
  +                            public void run() {
  +                                setToolTipText(toolTip);
  +                                MouseEvent e = new MouseEvent
  +                                    (JSVGCanvas.this,
  +                                     MouseEvent.MOUSE_MOVED,
  +                                     System.currentTimeMillis(),
  +                                     0,
  +                                     locationListener.getLastX(),
  +                                     locationListener.getLastY(),
  +                                     0,
  +                                     false);
  +                                ToolTipManager.sharedInstance().mouseMoved(e);
  +                            }
  +                        });
                   } else {
  -                    toolTip =
  -                        Messages.formatMessage
  -                        (TOOLTIP_DESC_ONLY,
  -                         new Object[]{toFormattedHTML(toolTip)});
  +                    EventQueue.invokeLater(new ToolTipRunnable(toolTip));
                   }
  -                
  -                setToolTip((Element)(elt.getParentNode()), toolTip);
               }
           }
   
  @@ -880,11 +962,11 @@
            * Checks if there is a peer element of a given type.  This returns the
            * first occurence of the given type or null if none is found.
            */
  -        public Element getPeerWithTag(Element elt,
  +        public Element getPeerWithTag(Element parent,
                                         String nameSpaceURI,
                                         String localName) {
   
  -            Element p = (Element)elt.getParentNode();
  +            Element p = (Element)parent;
               if (p == null) {
                   return null;
               }
  @@ -918,22 +1000,21 @@
            * Sets the tool tip on the input element.
            */
           public void setToolTip(Element elt, String toolTip){
  -            EventTarget target = (EventTarget)elt;
  -            elt.normalize();
  +            if (toolTipMap == null) {
  +                toolTipMap = new WeakHashMap();
  +            }
  +
  +            toolTipMap.put(elt, toolTip);
   
  -            // On mouseover, set the tooltip to the title value
  -            target.addEventListener(SVGConstants.SVG_EVENT_MOUSEOVER,
  -                                    new ToolTipModifier(toolTip, this),
  -                                    false);
  -
  -            // On mouseout, remove the tooltip
  -            target.addEventListener(SVGConstants.SVG_EVENT_MOUSEOUT,
  -                                    new ToolTipModifier(null, this),
  -                                    false);
  -
  -            if (locationListener == null) {
  -                locationListener = new LocationListener();
  -                addMouseMotionListener(locationListener);
  +            if (elt == lastTarget)
  +                EventQueue.invokeLater(new ToolTipRunnable(toolTip));
  +        }
  +
  +        public void removeToolTip(Element elt) {
  +            if (toolTipMap != null)
  +                toolTipMap.remove(elt);
  +            if (lastTarget == elt) { // clear ToolTip.
  +                EventQueue.invokeLater(new ToolTipRunnable(null));
               }
           }
   
  @@ -967,23 +1048,6 @@
                   dialog.setVisible(true); // Safe to be called from any thread
               }
           }
  -
  -        /**
  -         * Sets the time and element of the last tool tip event handled.
  -         */
  -        public void setLastToolTipEvent(long t, EventTarget et) {
  -            lastToolTipEventTimeStamp = t;
  -            lastToolTipEventTarget = et;
  -        }
  -
  -        /**
  -         * Checks if the specified event time and element are the same
  -         * as the last tool tip event.
  -         */
  -        public boolean matchLastToolTipEvent(long t, EventTarget et) {
  -            return lastToolTipEventTimeStamp == t
  -                && lastToolTipEventTarget == et;
  -        }
       }
   
       // ----------------------------------------------------------------------
  @@ -991,6 +1055,23 @@
       // ----------------------------------------------------------------------
   
       /**
  +     * Sets the time and element of the last tool tip event handled.
  +     */
  +    public void setLastToolTipEvent(long t, EventTarget et) {
  +        lastToolTipEventTimeStamp = t;
  +        lastToolTipEventTarget = et;
  +    }
  +
  +    /**
  +     * Checks if the specified event time and element are the same
  +     * as the last tool tip event.
  +     */
  +    public boolean matchLastToolTipEvent(long t, EventTarget et) {
  +        return lastToolTipEventTimeStamp == t
  +            && lastToolTipEventTarget == et;
  +    }
  +
  +    /**
        * Helper class. Simply keeps track of the last known mouse
        * position over the canvas.
        */
  @@ -998,6 +1079,10 @@
   
           protected int lastX, lastY;
   
  +        public LocationListener () { 
  +            lastX = 0; lastY = 0; 
  +        }
  +
           public void mouseMoved(MouseEvent evt) {
               lastX = evt.getX();
               lastY = evt.getY();
  @@ -1013,21 +1098,17 @@
       }
   
       /**
  -     * Sets a specific tooltip on the JSVGCanvas when a given event occurs. This
  -     * listener is used in the handleElement method to set, remove or modify the
  -     * JSVGCanvas tooltip on mouseover and on mouseout.<br/>
  +     * Sets a specific tooltip on the JSVGCanvas when a given event occurs. 
  +     * This listener is used in the handleElement method to set, remove or 
  +     * modify the JSVGCanvas tooltip on mouseover and on mouseout.<br/>
        *
        * Because we are on a single <tt>JComponent</tt> we trigger an artificial
  -     * <tt>MouseEvent</tt> when the toolTip is set to a non-null value, so as to
  -     * make sure it will show after the <tt>ToolTipManager</tt>'s default delay.
  +     * <tt>MouseEvent</tt> when the toolTip is set to a non-null value, so as 
  +     * to make sure it will show after the <tt>ToolTipManager</tt>'s default 
  +     * delay.
        */
       protected class ToolTipModifier implements EventListener {
           /**
  -         * Value of the toolTip
  -         */
  -        protected String toolTip;
  -
  -        /**
            * The CanvasUserAgent used to track the last tool tip event.
            */
           protected CanvasUserAgent canvasUserAgent;
  @@ -1038,40 +1119,81 @@
            * @param cua the CanvasUserAgent which will be used to track
            *        the last tool tip event.
            */
  -        public ToolTipModifier(String toolTip, CanvasUserAgent cua) {
  -            this.toolTip = toolTip;
  -            canvasUserAgent = cua;
  +        public ToolTipModifier() {
           }
   
           public void handleEvent(Event evt){
               // Don't set the tool tip if another ToolTipModifier
               // has already handled this event (as it will have been
               // a higher priority tool tip).
  -            if (canvasUserAgent.matchLastToolTipEvent(evt.getTimeStamp(),
  -                                                     evt.getTarget())) {
  +            if (matchLastToolTipEvent(evt.getTimeStamp(), evt.getTarget())) {
                   return;
               }
  -            canvasUserAgent.setLastToolTipEvent(evt.getTimeStamp(), 
  -                                                evt.getTarget());
  +            setLastToolTipEvent(evt.getTimeStamp(), evt.getTarget());
  +            EventTarget prevLastTarget = lastTarget;
  +            if (SVGConstants.SVG_EVENT_MOUSEOVER.equals(evt.getType())) {
  +                lastTarget = evt.getTarget();
  +            } else if (SVGConstants.SVG_EVENT_MOUSEOUT.equals(evt.getType())) {
  +                // related target is one it is entering or null.
  +                org.w3c.dom.events.MouseEvent mouseEvt;
  +                mouseEvt = ((org.w3c.dom.events.MouseEvent)evt);
  +                lastTarget = mouseEvt.getRelatedTarget(); 
  +            }
   
  -            EventQueue.invokeLater(new Runnable() {
  -                    public void run() {
  -                        setToolTipText(toolTip);
  -
  -                        if (toolTip != null) {
  -                            MouseEvent e = new MouseEvent
  -                                (JSVGCanvas.this,
  -                                 MouseEvent.MOUSE_ENTERED,
  -                                 System.currentTimeMillis(),
  -                                 0,
  -                                 locationListener.getLastX(),
  -                                 locationListener.getLastY(),
  -                                 0,
  -                                 false);
  -                            ToolTipManager.sharedInstance().mouseEntered(e);
  -                        }
  -                    }
  -                });
  +            if (toolTipMap != null) {
  +                Object o = toolTipMap.get(lastTarget);
  +                final String theToolTip;
  +                if (o == null) theToolTip = null;
  +                else           theToolTip = (String)o;
  +                if (prevLastTarget != lastTarget)
  +                    EventQueue.invokeLater(new ToolTipRunnable(theToolTip));
  +            }
  +        }
  +    }
  +
  +    protected class ToolTipRunnable implements Runnable {
  +        String theToolTip;
  +        public ToolTipRunnable(String toolTip) {
  +            this.theToolTip = toolTip;
  +        }
  +
  +        public void run() {
  +            setToolTipText(theToolTip);
  +
  +            MouseEvent e;
  +            if (theToolTip != null) {
  +                e = new MouseEvent
  +                    (JSVGCanvas.this,
  +                     MouseEvent.MOUSE_ENTERED,
  +                     System.currentTimeMillis(),
  +                     0,
  +                     locationListener.getLastX(),
  +                     locationListener.getLastY(),
  +                     0,
  +                     false);
  +                ToolTipManager.sharedInstance().mouseEntered(e);
  +                e = new MouseEvent
  +                    (JSVGCanvas.this,
  +                     MouseEvent.MOUSE_MOVED,
  +                     System.currentTimeMillis(),
  +                     0,
  +                     locationListener.getLastX(),
  +                     locationListener.getLastY(),
  +                     0,
  +                     false);
  +                ToolTipManager.sharedInstance().mouseMoved(e);
  +            } else {
  +                e = new MouseEvent
  +                    (JSVGCanvas.this,
  +                     MouseEvent.MOUSE_MOVED,
  +                     System.currentTimeMillis(),
  +                     0,
  +                     locationListener.getLastX(),
  +                     locationListener.getLastY(),
  +                     0,
  +                     false);
  +                ToolTipManager.sharedInstance().mouseMoved(e);
  +            }
           }
       }
   }
  
  
  
  1.101     +2 -2      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.100
  retrieving revision 1.101
  diff -u -r1.100 -r1.101
  --- JSVGComponent.java	14 Feb 2005 22:09:30 -0000	1.100
  +++ JSVGComponent.java	27 Feb 2005 02:08:52 -0000	1.101
  @@ -694,7 +694,7 @@
       /**
        * Starts a tree builder.
        */
  -    private void startGVTTreeBuilder() {
  +    protected void startGVTTreeBuilder() {
           gvtTreeBuilder = nextGVTTreeBuilder;
           nextGVTTreeBuilder = null;
           gvtTreeBuilder.start();
  
  
  
  1.1                  xml-batik/test-references/samples/tests/spec/scripting/pathLength.png
  
  	<<Binary file>>
  
  
  1.10      +2 -1      xml-batik/test-resources/org/apache/batik/test/interactiveSamples.xml
  
  Index: interactiveSamples.xml
  ===================================================================
  RCS file: /home/cvs/xml-batik/test-resources/org/apache/batik/test/interactiveSamples.xml,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- interactiveSamples.xml	18 Aug 2004 07:16:31 -0000	1.9
  +++ interactiveSamples.xml	27 Feb 2005 02:08:52 -0000	1.10
  @@ -37,6 +37,7 @@
   
       <testGroup id="tests.spec.scripting" name="Interactive Scripting Tests"
                  class="org.apache.batik.test.svg.JSVGRenderingAccuracyTest">
  +        <test id="samples/tests/spec/scripting/addDescOnClick.svg" />
           <test id="samples/tests/spec/scripting/bug12933.svg" />
           <test id="samples/tests/spec/scripting/filterPatternUpdate.svg" />
           <test id="samples/tests/spec/scripting/gradientsUpdate.svg" />
  
  
  
  1.126     +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.125
  retrieving revision 1.126
  diff -u -r1.125 -r1.126
  --- samplesRendering.xml	12 Feb 2005 01:48:24 -0000	1.125
  +++ samplesRendering.xml	27 Feb 2005 02:08:52 -0000	1.126
  @@ -373,6 +373,7 @@
           <test id="samples/tests/spec/scripting/line.svg" />
           <test id="samples/tests/spec/scripting/nestedsvg.svg" />
           <test id="samples/tests/spec/scripting/path.svg" />
  +        <test id="samples/tests/spec/scripting/pathLength.svg" />
           <test id="samples/tests/spec/scripting/path_pathSegList_create.svg" />
           <test id="samples/tests/spec/scripting/path_pathSegList1.svg" />
           <test id="samples/tests/spec/scripting/path_pathSegList2.svg" />
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: batik-dev-unsubscribe@xml.apache.org
For additional commands, e-mail: batik-dev-help@xml.apache.org