vhardy 2003/07/09 06:31:45 Modified: samples/tests/spec/scripting use.svg test-references/samples/tests/spec/scripting use.png sources/org/apache/batik/bridge SVGUseElementBridge.java Log: Fixed bug 21358. It is now possible (even though sub-optimal) to modify the xlink:href on a <use> and to modify the content referenced by a <use>. See the samples/tests/spec/scripting/use.svg sample. New reference image for test. Revision Changes Path 1.3 +90 -24 xml-batik/samples/tests/spec/scripting/use.svg Index: use.svg =================================================================== RCS file: /home/cvs/xml-batik/samples/tests/spec/scripting/use.svg,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- use.svg 24 Jul 2002 11:50:25 -0000 1.2 +++ use.svg 9 Jul 2003 13:31:42 -0000 1.3 @@ -24,18 +24,57 @@ <text x="50%" y="45" class="title">x/y/transform update on <use></text> <script type="text/ecmascript"> <![CDATA[ + var xlinkNS = 'http://www.w3.org/1999/xlink'; + var svgNS = 'http://www.w3.org/2000/svg'; function runTest(){ document.getElementById('x').setAttributeNS(null, 'x', '20'); document.getElementById('y').setAttributeNS(null, 'y', '15'); document.getElementById('transform').setAttributeNS(null, 'transform', 'rotate(20)'); + document.getElementById('xlink').setAttributeNS(xlinkNS, 'xlink:href', '#symbol2'); + + var mutated = document.getElementById('mutatedSymbol'); + while(mutated.firstChild != null) { + mutated.removeChild(mutated.firstChild); + } + var r = document.createElementNS(svgNS, 'rect'); + r.setAttributeNS(null, "x", "-10"); + r.setAttributeNS(null, "y", "-10"); + r.setAttributeNS(null, "width", "20"); + r.setAttributeNS(null, "height", "20"); + r.setAttributeNS(null, "stroke-width", "4"); + r.setAttributeNS(null, "stroke", "gold"); + r.setAttributeNS(null, "fill", "crimson"); + mutated.appendChild(r); + + var t = document.createElementNS(svgNS, "text"); + mutated.appendChild(t); + t.setAttributeNS(null, "text-anchor", "middle"); + t.setAttributeNS(null, "fill", "gold"); + t.setAttributeNS(null, "stroke", "none"); + t.setAttributeNS(null, "y", "5"); + var msg = document.createTextNode("Hello"); + t.appendChild(msg); + + msg.data = "Hi"; } - ]]> </script> + ]]> </script> <rect id="symbol" x="-10" y="-10" width="20" height="20" /> + <defs> <rect id="symbol" x="-10" y="-10" width="20" height="20" /> + <rect id="symbol2" x="-10" y="-10" width="20" height="20" stroke-width="4" stroke="gold" fill="crimson" /> + + <g id="mutatedSymbolReference"> + <rect x="-10" y="-10" width="20" height="20" stroke-width="4" stroke="gold" fill="crimson" /> + <text text-anchor="middle" y="5" fill="gold" stroke="none">Hi</text> + </g> + + <g id="mutatedSymbol"> + <rect x="-12" y="-12" width="24" height="24" class="reference" /> + </g> <rect id="titleCell" x="-60" y="-15" width="120" height="20" /> <rect id="tableCell" x="-60" y="-20" width="120" height="40" /> @@ -90,7 +129,7 @@ ]]></style> - <g transform="translate(165, 160)"> + <g transform="translate(165, 120)"> <g id="tableHeader" class="tableHeader"> <g> <use class="tableHeader" xlink:href="#titleCell" /> @@ -147,31 +186,58 @@ </g> - <g onclick="runTest()"> + <g id="xlinkRow" transform="translate(0,145)"> + <g> + <use class="tableCell" xlink:href="#tableCell" /> + <text class="tableCell">xlink:href</text> + </g> + + <g transform="translate(120,0)" > + <use class="tableCell" xlink:href="#tableCell" /> + <use id="xlink" + x="5" y="0" class="symbol" xlink:href="#symbol"/> + <use x="5" y="0" class="reference" xlink:href="#symbol"/> + </g> + + </g> + + <g id="mutation" transform="translate(0,185)"> + <g> + <use class="tableCell" xlink:href="#tableCell" /> + <text class="tableCell">mutation</text> + </g> + + <g transform="translate(120,0)" > + <use class="tableCell" xlink:href="#tableCell" /> + <use id="xlink" + x="-25" y="0" class="symbol" xlink:href="#mutatedSymbolReference"/> + <use x="25" y="0" class="reference" xlink:href="#mutatedSymbol"/> + </g> + + </g> + + <g onclick="runTest()" transform="translate(0, 80)"> <use class="button" xlink:href="#button" x="60" y="200" /> <text class="button" x="60" y="200">Run Test</text> </g> </g> -<!-- - <use id="use" xlink:href="#Rect" x="20" y="40" width="100" height="80" - transform="scale(1.2)" onclick="scale('use')" /> - - <a onclick="removeChangeAdd('use')"> - <text x="80" y="35" text-anchor="middle">Remove, modify, add</text> - </a> - - <a onclick="removeChangeAdd('rect')" transform="translate(160,0)"> - <text x="80" y="35" text-anchor="middle">Remove, modify, add</text> - </a> - - <rect id="rect" x="150" y="40" width="100" height="80" transform="scale(1.2)" - style="fill:green; stroke:yellow" onclick="scale('rect')" /> - - - <text x="175" y="190" style="font-size:20pt; text-anchor:middle"> - Transform problem. - </text> ---> + + + <script type="text/ecmascript"><![CDATA[ +function onDone() { + if (!(regardTestInstance == null)) { + regardTestInstance.scriptDone(); + } else { + alert("This button only works when run in the regard framework"); + } +} + ]]></script> + <g id="done" transform="translate(195, 468)" cursor="pointer" onclick="onDone()"> + <rect rx="5" ry="5" width="60" height="25" fill="#eeeeee" stroke="black" /> + <text x="30" y="18" font-size="14" font-weight="bold" text-anchor="middle">Done</text> + </g> + + </svg> 1.3 +26 -28 xml-batik/test-references/samples/tests/spec/scripting/use.png <<Binary file>> 1.33 +113 -2 xml-batik/sources/org/apache/batik/bridge/SVGUseElementBridge.java Index: SVGUseElementBridge.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/bridge/SVGUseElementBridge.java,v retrieving revision 1.32 retrieving revision 1.33 diff -u -r1.32 -r1.33 --- SVGUseElementBridge.java 11 Jun 2003 22:07:25 -0000 1.32 +++ SVGUseElementBridge.java 9 Jul 2003 13:31:44 -0000 1.33 @@ -34,6 +34,12 @@ * @version $Id$ */ public class SVGUseElementBridge extends AbstractGraphicsNodeBridge { + /* + * Used to handle mutation of the referenced content. This is + * only used in dynamic context and only for reference to local + * content. + */ + protected ReferencedElementMutationListener l; /** * Constructs a new bridge for the <use> element. @@ -67,6 +73,25 @@ return null; } + CompositeGraphicsNode gn = buildCompositeGraphicsNode(ctx, e, + null, null); + + return gn; + } + + /** + * Creates a <tt>GraphicsNode</tt> from the input element and + * populates the input <tt>CompositeGraphicsNode</tt> + * + * @param ctx the bridge context to use + * @param e the element that describes the graphics node to build + * @param gn the CompositeGraphicsNode where the use graphical + * content will be appended. The composite node is emptied + * before appending new content. + */ + public CompositeGraphicsNode buildCompositeGraphicsNode(BridgeContext ctx, Element e, + CompositeGraphicsNode gn, + ReferencedElementMutationListener l) { // get the referenced element String uri = XLinkSupport.getXLinkHref(e); if (uri.length() == 0) @@ -142,8 +167,19 @@ GraphicsNode refNode = builder.build(ctx, g); /////////////////////////////////////////////////////////////////////// + boolean update = true; + if (gn == null) { + gn = new CompositeGraphicsNode(); + update = false; + } + + if (update) { + int s = gn.size(); + for (int i=0; i<s; i++) { + gn.remove(0); + } + } - CompositeGraphicsNode gn = new CompositeGraphicsNode(); gn.getChildren().add(refNode); gn.setTransform(computeTransform(e, ctx)); @@ -159,6 +195,59 @@ if (r != null) { gn.setBackgroundEnable(r); } + + /////////////////////////////////////////////////////////////////////// + + // Handle mutations on content referenced in the same file if + // we are in a dynamic context. + if (isLocal && ctx.isDynamic()) { + if (l == null) { + l = new ReferencedElementMutationListener(); + l.target = (EventTarget)refElement; + } else { + // Remove event listeners + EventTarget target = l.target; + target.removeEventListener("DOMAttrModified", + l, + true); + + target.removeEventListener("DOMNodeInserted", + l, + true); + + target.removeEventListener("DOMNodeRemoved", + l, + true); + + target.removeEventListener("DOMCharacterDataModified", + l, + true); + } + + EventTarget target = (EventTarget)refElement; + l.target = target; + + target.addEventListener("DOMAttrModified", + l, + true); + ctx.storeEventListener(target, "DOMAttrModified", l, true); + + target.addEventListener("DOMNodeInserted", + l, + true); + ctx.storeEventListener(target, "DOMNodeInserted", l, true); + + target.addEventListener("DOMNodeRemoved", + l, + true); + ctx.storeEventListener(target, "DOMNodeRemoved", l, true); + + target.addEventListener("DOMCharacterDataModified", + l, + true); + ctx.storeEventListener(target, "DOMCharacterDataModified", l, true); + } + return gn; } @@ -262,6 +351,22 @@ } } + /** + * Used to handle modifications to the referenced content + */ + public class ReferencedElementMutationListener implements EventListener { + EventTarget target; + + public void handleEvent(Event evt) { + // We got a mutation in the referenced content. We need to + // build the content again, just in case. + // Note that this is way sub-optimal, because multiple changes + // to the referenced content will cause multiple updates to the + // referencing <use>. However, this provides the desired behavior + buildCompositeGraphicsNode(ctx, e, (CompositeGraphicsNode)node, this); + } + } + // BridgeUpdateHandler implementation ////////////////////////////////// /** @@ -269,12 +374,18 @@ */ public void handleDOMAttrModifiedEvent(MutationEvent evt) { String attrName = evt.getAttrName(); + Node evtNode = evt.getRelatedNode(); + if (attrName.equals(SVG_X_ATTRIBUTE) || attrName.equals(SVG_Y_ATTRIBUTE) || attrName.equals(SVG_TRANSFORM_ATTRIBUTE)) { String s = evt.getNewValue(); node.setTransform(computeTransform(e, ctx)); handleGeometryChanged(); + } else if (( XLinkSupport.XLINK_NAMESPACE_URI.equals + (evtNode.getNamespaceURI()) ) + && SVG_HREF_ATTRIBUTE.equals(evtNode.getLocalName()) ){ + buildCompositeGraphicsNode(ctx, e, (CompositeGraphicsNode)node, l); } } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]