Branch to show framework for dependency tracking for at least gradients git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/batik/branches/depend-track@468881 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/samples/tests/spec/scripting/gradients.svg b/samples/tests/spec/scripting/gradients.svg new file mode 100755 index 0000000..a8d17dd --- /dev/null +++ b/samples/tests/spec/scripting/gradients.svg
@@ -0,0 +1,115 @@ +<?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 2000-2001,2003 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 modifying gradients. --> +<!-- --> +<!-- @author Thomas.DeWeese@apache.org --> +<!-- @version $Id: anne.svg 201439 2005-04-01 02:28:17Z deweese $ --> +<!-- ====================================================================== --> + +<?xml-stylesheet type="text/css" href="../../resources/style/test.css" ?> + +<svg width="450" height="500" viewBox="0 0 450 500" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" > + <!-- ============================================================= --> + <!-- Test content --> + <!-- ============================================================= --> + <title>Dynamic change of gradient</title> + + <text x="50%" y="45" class="title">Dynamic change of gradient</text> + + <script type="text/ecmascript"> + var svgNS = "http://www.w3.org/2000/svg"; + var xlinkNS = "http://www.w3.org/1999/xlink"; + + function toggleAttr(id, ns, attr, v1, v2) { + var e = document.getElementById(id); + var a = e.getAttributeNS(ns, attr); + e.setAttributeNS(ns, attr, (a==v1)?v2:v1); + } + </script> + + <defs> + <linearGradient id="baseLG1"> + <stop id="stop10" style="stop-color:crimson" offset="0" /> + <stop id="stop11" style="stop-color:gold" offset="1" /> + </linearGradient> + + <linearGradient id="baseLG2"> + <stop id="stop20" stop-color="crimson" offset="0" /> + <stop id="stop21" stop-color="gold" offset="1" /> + </linearGradient> + + <linearGradient id="baseLG3"> + <stop id="stop30" stop-color="gold" offset="0" /> + <stop id="stop31" stop-color="crimson" offset="1" /> + </linearGradient> + + <linearGradient id="lg1" xlink:href="#baseLG1" + x1="0" y1=".5" x2="1" y2=".5"/> + + <linearGradient id="lg2" xlink:href="#baseLG2" + x1=".5" y1="0" x2=".5" y2="1"/> + + <linearGradient id="lg3-1" xlink:href="#baseLG1" + x1="0" y1=".5" x2="1" y2=".5"/> + <linearGradient id="lg3" xlink:href="#lg3-1"/> + </defs> + + <rect x="12.5" y="75" width="100" height="75" fill="url(#lg1)" + onclick="toggleAttr('stop10', null, 'style', + 'stop-color:blue', 'stop-color:crimson')"/> + + <rect x="137.5" y="75" width="100" height="75" fill="url(#lg1)" + onclick="toggleAttr('stop10', null, 'style', + 'stop-color:blue', 'stop-color:crimson')"/> + + <text x="260" y="100" >Both Rects indirectly reference + <tspan x="260" y="115">same gradient where 'style' is</tspan> + <tspan x="260" y="130">modified 'onclick'</tspan></text> + + <rect x="12.5" y="175" width="100" height="75" fill="url(#lg2)" + onclick="toggleAttr('stop20', null, 'stop-color', + 'blue', 'crimson')"/> + + <rect x="137.5" y="175" width="100" height="75" fill="url(#lg2)" + onclick="toggleAttr('stop20', null, 'stop-color', + 'blue', 'crimson')"/> + + <text x="260" y="200" >Both Rects indirectly reference + <tspan x="260" y="215">same gradient where 'stop-color'</tspan> + <tspan x="260" y="230">is modified 'onclick'</tspan></text> + + <rect x="12.5" y="275" width="100" height="75" fill="url(#lg3)" + onclick="toggleAttr('lg3-1', xlinkNS, 'href', + '#baseLG3', '#baseLG1')"/> + + <rect x="137.5" y="275" width="100" height="75" fill="url(#lg3)" + onclick="toggleAttr('lg3-1', xlinkNS, 'href', + '#baseLG3', '#baseLG1')"/> + + <text x="260" y="300" >Both Rects indirectly reference + <tspan x="260" y="315">gradient where 'xlink:href'</tspan> + <tspan x="260" y="330">is modified 'onclick'</tspan></text> + +</svg> \ No newline at end of file
diff --git a/sources/org/apache/batik/bridge/AbstractSVGFilterPrimitiveElementBridge.java b/sources/org/apache/batik/bridge/AbstractSVGFilterPrimitiveElementBridge.java index c8c39ee..7149ccb 100644 --- a/sources/org/apache/batik/bridge/AbstractSVGFilterPrimitiveElementBridge.java +++ b/sources/org/apache/batik/bridge/AbstractSVGFilterPrimitiveElementBridge.java
@@ -184,7 +184,7 @@ } else if (SVG_STROKE_PAINT_VALUE.equals(s)) { // StrokePaint Paint paint = PaintServer.convertStrokePaint - (filteredElement,filteredNode, ctx); + (filteredElement,filteredNode, null, ctx); // <!> FIXME: Should we create a transparent flood ??? source = new FloodRable8Bit(filterRegion, paint); } @@ -209,9 +209,9 @@ if (SVG_FILL_PAINT_VALUE.equals(s)) { // FillPaint Paint paint = PaintServer.convertFillPaint - (filteredElement,filteredNode, ctx); + (filteredElement,filteredNode, null, ctx); if (paint == null) { - paint = new Color(0, 0, 0, 0); // create a transparent flood + paint = new Color(0, 0, 0, 0); // create transparent flood } source = new FloodRable8Bit(filterRegion, paint); }
diff --git a/sources/org/apache/batik/bridge/AbstractSVGGradientElementBridge.java b/sources/org/apache/batik/bridge/AbstractSVGGradientElementBridge.java index b55538a..a778c6c 100644 --- a/sources/org/apache/batik/bridge/AbstractSVGGradientElementBridge.java +++ b/sources/org/apache/batik/bridge/AbstractSVGGradientElementBridge.java
@@ -24,6 +24,7 @@ import java.util.LinkedList; import java.util.List; +import org.apache.batik.css.engine.CSSEngineEvent; import org.apache.batik.dom.svg.SVGOMDocument; import org.apache.batik.dom.svg.XMLBaseSupport; import org.apache.batik.dom.util.XLinkSupport; @@ -33,6 +34,13 @@ import org.w3c.dom.Element; import org.w3c.dom.Node; +import java.util.Iterator; +import java.util.List; +import java.util.ArrayList; +import org.w3c.dom.events.Event; +import org.w3c.dom.events.EventTarget; +import org.w3c.dom.events.EventListener; + /** * Bridge class for vending gradients. * @@ -61,8 +69,10 @@ Element paintedElement, GraphicsNode paintedNode, float opacity) { - String s; + if (ctx.isDynamic()) { + if(wl == null) wl = new WatchList(); + } // stop elements List stops = extractStop(paintElement, opacity, ctx); @@ -117,6 +127,7 @@ colors, offsets, ctx); + if (wl != null) wl.addListener(ml, ctx); return paint; } @@ -177,14 +188,20 @@ * @param opacity the opacity * @param ctx the bridge context to use */ - protected static List extractStop(Element paintElement, - float opacity, - BridgeContext ctx) { + protected List extractStop(Element paintElement, + float opacity, + BridgeContext ctx) { List refs = new LinkedList(); for (;;) { List stops = extractLocalStop(paintElement, opacity, ctx); if (stops != null) { + if (wl != null) { + EventTarget et = (EventTarget)paintElement; + wl.addToWatchList(et, "DOMAttrModified"); + wl.addToWatchList(et, "DOMNodeInserted"); + wl.addToWatchList(et, "DOMNodeRemoved"); + } return stops; // stop elements found, exit } String uri = XLinkSupport.getXLinkHref(paintElement); @@ -201,6 +218,12 @@ new Object[] {uri}); } refs.add(purl); + + if ((wl != null) && (hostBridge != null)) { + EventTarget et = (EventTarget)paintElement; + wl.addToWatchList(et, "DOMAttrModified"); + } + paintElement = ctx.getReferencedElement(paintElement, uri); } } @@ -325,8 +348,38 @@ } Color color = CSSUtilities.convertStopColor(stopElement, opacity, ctx); - + // System.err.println("Stop Color: " + color); return new Stop(color, offset); } } + + AbstractGraphicsNodeBridge hostBridge; + int cssProperty; + public WatchList wl; + public MutationListener ml = new MutationListener(); + + public void setHostInfo(AbstractGraphicsNodeBridge hostBridge, + int cssProperty) { + this.hostBridge = hostBridge; + this.cssProperty = cssProperty; + } + + /** + * Used to handle modifications to the referenced content + */ + public class MutationListener implements EventListener { + public void handleEvent(Event evt) { + wl.dispose(); + // System.err.println("Twiddleing: " + cssProperty + + // " On: " + hostBridge); + BridgeContext ctx = hostBridge.ctx; + Element hostElem = hostBridge.e; + CSSEngineEvent cssEvt = new CSSEngineEvent + (ctx.getCSSEngineForElement(hostElem), + hostElem, new int[] {cssProperty}); + hostBridge.handleCSSEngineEvent(cssEvt); + } + } + + }
diff --git a/sources/org/apache/batik/bridge/PaintServer.java b/sources/org/apache/batik/bridge/PaintServer.java index 78ee74e..22e5f34 100644 --- a/sources/org/apache/batik/bridge/PaintServer.java +++ b/sources/org/apache/batik/bridge/PaintServer.java
@@ -137,13 +137,15 @@ * @param node the shape node * @param ctx the bridge context */ - public static ShapePainter convertFillAndStroke(Element e, - ShapeNode node, - BridgeContext ctx) { + public static ShapePainter convertFillAndStroke + (Element e, ShapeNode node, + AbstractGraphicsNodeBridge b, + BridgeContext ctx) { + Shape shape = node.getShape(); if (shape == null) return null; - Paint fillPaint = convertFillPaint (e, node, ctx); + Paint fillPaint = convertFillPaint (e, node, b, ctx); FillShapePainter fp = new FillShapePainter(shape); fp.setPaint(fillPaint); @@ -151,7 +153,7 @@ if (stroke == null) return fp; - Paint strokePaint = convertStrokePaint(e, node, ctx); + Paint strokePaint = convertStrokePaint(e, node, b, ctx); StrokeShapePainter sp = new StrokeShapePainter(shape); sp.setStroke(stroke); sp.setPaint(strokePaint); @@ -163,9 +165,12 @@ } - public static ShapePainter convertStrokePainter(Element e, - ShapeNode node, - BridgeContext ctx) { + public static ShapePainter convertStrokePainter + (Element e, + ShapeNode node, + AbstractGraphicsNodeBridge b, + BridgeContext ctx) { + Shape shape = node.getShape(); if (shape == null) return null; @@ -173,7 +178,7 @@ if (stroke == null) return null; - Paint strokePaint = convertStrokePaint(e, node, ctx); + Paint strokePaint = convertStrokePaint(e, node, b, ctx); StrokeShapePainter sp = new StrokeShapePainter(shape); sp.setStroke(stroke); sp.setPaint(strokePaint); @@ -194,6 +199,7 @@ */ public static Paint convertStrokePaint(Element strokedElement, GraphicsNode strokedNode, + AbstractGraphicsNodeBridge b, BridgeContext ctx) { Value v = CSSUtilities.getComputedStyle (strokedElement, SVGCSSEngine.STROKE_OPACITY_INDEX); @@ -205,6 +211,8 @@ strokedNode, v, opacity, + SVGCSSEngine.STROKE_INDEX, + b, ctx); } @@ -218,6 +226,7 @@ */ public static Paint convertFillPaint(Element filledElement, GraphicsNode filledNode, + AbstractGraphicsNodeBridge b, BridgeContext ctx) { Value v = CSSUtilities.getComputedStyle (filledElement, SVGCSSEngine.FILL_OPACITY_INDEX); @@ -229,6 +238,8 @@ filledNode, v, opacity, + SVGCSSEngine.FILL_INDEX, + b, ctx); } @@ -243,10 +254,12 @@ * @param ctx the bridge context */ public static Paint convertPaint(Element paintedElement, - GraphicsNode paintedNode, - Value paintDef, - float opacity, - BridgeContext ctx) { + GraphicsNode paintedNode, + Value paintDef, + float opacity, + int cssPropIndex, + AbstractGraphicsNodeBridge b, + BridgeContext ctx) { if (paintDef.getCssValueType() == CSSValue.CSS_PRIMITIVE_VALUE) { switch (paintDef.getPrimitiveType()) { case CSSPrimitiveValue.CSS_IDENT: @@ -260,6 +273,8 @@ paintedNode, paintDef, opacity, + cssPropIndex, + b, ctx); default: @@ -276,7 +291,10 @@ case CSSPrimitiveValue.CSS_URI: { Paint result = silentConvertURIPaint(paintedElement, paintedNode, - v, opacity, ctx); + v, opacity, + cssPropIndex, + b, + ctx); if (result != null) return result; v = paintDef.item(1); @@ -319,11 +337,13 @@ GraphicsNode paintedNode, Value paintDef, float opacity, + int cssPropIndex, + AbstractGraphicsNodeBridge b, BridgeContext ctx) { Paint paint = null; try { paint = convertURIPaint(paintedElement, paintedNode, - paintDef, opacity, ctx); + paintDef, opacity, cssPropIndex, b, ctx); } catch (BridgeException ex) { } return paint; @@ -342,6 +362,8 @@ GraphicsNode paintedNode, Value paintDef, float opacity, + int cssPropIndex, + AbstractGraphicsNodeBridge b, BridgeContext ctx) { String uri = paintDef.getStringValue(); @@ -352,6 +374,12 @@ throw new BridgeException(paintedElement, ERR_CSS_URI_BAD_TARGET, new Object[] {uri}); } + + if (bridge instanceof AbstractSVGGradientElementBridge) { + ((AbstractSVGGradientElementBridge)bridge).setHostInfo + (b, cssPropIndex); + } + return ((PaintBridge)bridge).createPaint(ctx, paintElement, paintedElement,
diff --git a/sources/org/apache/batik/bridge/SVGLineElementBridge.java b/sources/org/apache/batik/bridge/SVGLineElementBridge.java index 42c6c9e..1caf527 100644 --- a/sources/org/apache/batik/bridge/SVGLineElementBridge.java +++ b/sources/org/apache/batik/bridge/SVGLineElementBridge.java
@@ -73,7 +73,7 @@ // 'stroke-miterlimit' // 'stroke-dasharray' // 'stroke-dashoffset' - return PaintServer.convertStrokePainter(e, shapeNode, ctx); + return PaintServer.convertStrokePainter(e, shapeNode, this, ctx); } /**
diff --git a/sources/org/apache/batik/bridge/SVGLinearGradientElementBridge.java b/sources/org/apache/batik/bridge/SVGLinearGradientElementBridge.java index 9834810..35d845e 100644 --- a/sources/org/apache/batik/bridge/SVGLinearGradientElementBridge.java +++ b/sources/org/apache/batik/bridge/SVGLinearGradientElementBridge.java
@@ -48,6 +48,10 @@ return SVG_LINEAR_GRADIENT_TAG; } + public Bridge getInstance() { + return new SVGLinearGradientElementBridge(); + } + /** * Builds a linear gradient according to the specified parameters. *
diff --git a/sources/org/apache/batik/bridge/SVGRadialGradientElementBridge.java b/sources/org/apache/batik/bridge/SVGRadialGradientElementBridge.java index eee81ba..a29e17e 100644 --- a/sources/org/apache/batik/bridge/SVGRadialGradientElementBridge.java +++ b/sources/org/apache/batik/bridge/SVGRadialGradientElementBridge.java
@@ -49,6 +49,10 @@ return SVG_RADIAL_GRADIENT_TAG; } + public Bridge getInstance() { + return new SVGRadialGradientElementBridge(); + } + /** * Builds a radial gradient according to the specified parameters. *
diff --git a/sources/org/apache/batik/bridge/SVGShapeElementBridge.java b/sources/org/apache/batik/bridge/SVGShapeElementBridge.java index cf6eaf2..3ff12a5 100644 --- a/sources/org/apache/batik/bridge/SVGShapeElementBridge.java +++ b/sources/org/apache/batik/bridge/SVGShapeElementBridge.java
@@ -110,7 +110,7 @@ // 'stroke-miterlimit' // 'stroke-dasharray' // 'stroke-dashoffset' - return PaintServer.convertFillAndStroke(e, shapeNode, ctx); + return PaintServer.convertFillAndStroke(e, shapeNode, this, ctx); } /**
diff --git a/sources/org/apache/batik/bridge/SVGTextElementBridge.java b/sources/org/apache/batik/bridge/SVGTextElementBridge.java index 65d1a2f..97da48e 100644 --- a/sources/org/apache/batik/bridge/SVGTextElementBridge.java +++ b/sources/org/apache/batik/bridge/SVGTextElementBridge.java
@@ -1731,8 +1731,10 @@ pi.composite = AlphaComposite.SrcOver; pi.visible = CSSUtilities.convertVisibility(element); - pi.fillPaint = PaintServer.convertFillPaint (element, node, ctx); - pi.strokePaint = PaintServer.convertStrokePaint(element, node, ctx); + pi.fillPaint = PaintServer.convertFillPaint + (element, node, this, ctx); + pi.strokePaint = PaintServer.convertStrokePaint + (element, node, this, ctx); pi.strokeStroke = PaintServer.convertStroke (element); }
diff --git a/sources/org/apache/batik/bridge/WatchList.java b/sources/org/apache/batik/bridge/WatchList.java new file mode 100755 index 0000000..f31c967 --- /dev/null +++ b/sources/org/apache/batik/bridge/WatchList.java
@@ -0,0 +1,90 @@ +/* + + Copyright 2006 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.util.Iterator; +import java.util.HashSet; +import java.util.Set; + +import org.w3c.dom.events.EventTarget; +import org.w3c.dom.events.EventListener; + +/** + * One line Class Desc + * + * Complete Class Desc + * + * @author <a href="mailto:deweese@apache.org>deweese</a> + * @version $Id: skel.el,v 1.1 2003/05/13 21:04:46 deweese Exp $ + */ +public class WatchList { + + public Set toWatch = new HashSet(); + public EventListener el; + + public WatchList() { + } + + static class WatchPair { + public EventTarget et; + public String eventType; + + WatchPair(EventTarget et, String eventType) { + this.et = et; + this.eventType = eventType; + } + + public boolean equals(Object obj) { + if (obj instanceof WatchPair) { + WatchPair wp = (WatchPair)obj; + return ((et == wp.et) && (eventType == wp.eventType)); + } + return false; + } + + public int hashCode() { + return et.hashCode() ^ eventType.hashCode(); + } + }; + + public void addToWatchList(EventTarget et, String eventType) { + if (el != null) + throw new IllegalStateException + ("Can't add to watch list after attaching listeners"); + toWatch.add(new WatchPair(et, eventType)); + } + + public void addListener(EventListener l, BridgeContext ctx) { + Iterator iter = toWatch.iterator(); + while (iter.hasNext()) { + WatchPair wp = (WatchPair)iter.next(); + wp.et.addEventListener(wp.eventType, l, false); + ctx.storeEventListener(wp.et, wp.eventType, l, false); + } + el = l; + } + + public void dispose() { + Iterator iter = toWatch.iterator(); + while (iter.hasNext()) { + WatchPair wp = (WatchPair)iter.next(); + wp.et.removeEventListener(wp.eventType, el, false); + } + } +};
diff --git a/sources/org/apache/batik/css/engine/CSSEngine.java b/sources/org/apache/batik/css/engine/CSSEngine.java index a3f5454..f2b9f40 100644 --- a/sources/org/apache/batik/css/engine/CSSEngine.java +++ b/sources/org/apache/batik/css/engine/CSSEngine.java
@@ -434,7 +434,7 @@ domAttrModifiedListener = new DOMAttrModifiedListener(); et.addEventListener("DOMAttrModified", domAttrModifiedListener, - false); + true); domNodeInsertedListener = new DOMNodeInsertedListener(); et.addEventListener("DOMNodeInserted", domNodeInsertedListener,
diff --git a/sources/org/apache/batik/dom/svg/SVGOMGradientElement.java b/sources/org/apache/batik/dom/svg/SVGOMGradientElement.java index 5f3766e..0ade59b 100644 --- a/sources/org/apache/batik/dom/svg/SVGOMGradientElement.java +++ b/sources/org/apache/batik/dom/svg/SVGOMGradientElement.java
@@ -146,7 +146,5 @@ /** * Returns a new uninitialized instance of this object's class. */ - protected Node newNode() { - return new SVGOMAElement(); - } + protected abstract Node newNode(); }
diff --git a/sources/org/apache/batik/dom/svg/SVGStylableElement.java b/sources/org/apache/batik/dom/svg/SVGStylableElement.java index c86c963..356270d 100644 --- a/sources/org/apache/batik/dom/svg/SVGStylableElement.java +++ b/sources/org/apache/batik/dom/svg/SVGStylableElement.java
@@ -83,6 +83,7 @@ * Sets the computed style of this element/pseudo-element. */ public void setComputedStyleMap(String pseudoElement, StyleMap sm) { + // new Exception("SetStyle: " + sm).printStackTrace(); computedStyleMap = sm; }