-/*******************************************************************************\r
- * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
package org.simantics.scenegraph.g2d.nodes;
-\r
-import java.awt.Graphics2D;\r
-import java.awt.Point;\r
-import java.awt.geom.AffineTransform;\r
-import java.awt.geom.Rectangle2D;\r
-import java.io.ByteArrayInputStream;\r
-import java.io.IOException;\r
-import java.lang.ref.WeakReference;\r
-import java.math.BigInteger;\r
-import java.net.URI;\r
-import java.net.URL;\r
-import java.security.MessageDigest;\r
-import java.security.NoSuchAlgorithmException;\r
-import java.util.ArrayList;\r
-import java.util.HashMap;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.WeakHashMap;\r
-\r
-import org.simantics.scenegraph.ExportableWidget.RasterOutputWidget;\r
-import org.simantics.scenegraph.LoaderNode;\r
-import org.simantics.scenegraph.ScenegraphUtils;\r
-import org.simantics.scenegraph.g2d.G2DNode;\r
-import org.simantics.scenegraph.utils.BufferedImage;\r
-import org.simantics.scenegraph.utils.G2DUtils;\r
-import org.simantics.scenegraph.utils.InitValueSupport;\r
-import org.simantics.scenegraph.utils.MipMapBufferedImage;\r
-import org.simantics.scenegraph.utils.MipMapVRamBufferedImage;\r
-import org.simantics.scenegraph.utils.VRamBufferedImage;\r
-import org.simantics.scl.runtime.function.Function1;\r
-import org.simantics.scl.runtime.function.Function2;\r
-import org.simantics.utils.threads.AWTThread;\r
-\r
-import com.kitfox.svg.SVGCache;\r
-import com.kitfox.svg.SVGDiagram;\r
-import com.kitfox.svg.SVGElement;\r
-import com.kitfox.svg.SVGException;\r
-import com.kitfox.svg.SVGRoot;\r
-import com.kitfox.svg.SVGUniverse;\r
-import com.kitfox.svg.Text;\r
-import com.kitfox.svg.Tspan;\r
-import com.kitfox.svg.animation.AnimationElement;\r
-\r
+
+import java.awt.Graphics2D;
+import java.awt.Point;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.lang.ref.WeakReference;
+import java.math.BigInteger;
+import java.net.URI;
+import java.net.URL;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.WeakHashMap;
+
+import org.simantics.scenegraph.ExportableWidget.RasterOutputWidget;
+import org.simantics.scenegraph.LoaderNode;
+import org.simantics.scenegraph.ScenegraphUtils;
+import org.simantics.scenegraph.g2d.G2DNode;
+import org.simantics.scenegraph.utils.BufferedImage;
+import org.simantics.scenegraph.utils.G2DUtils;
+import org.simantics.scenegraph.utils.InitValueSupport;
+import org.simantics.scenegraph.utils.MipMapBufferedImage;
+import org.simantics.scenegraph.utils.MipMapVRamBufferedImage;
+import org.simantics.scenegraph.utils.VRamBufferedImage;
+import org.simantics.scl.runtime.function.Function1;
+import org.simantics.scl.runtime.function.Function2;
+import org.simantics.utils.threads.AWTThread;
+
+import com.kitfox.svg.RenderableElement;
+import com.kitfox.svg.SVGCache;
+import com.kitfox.svg.SVGDiagram;
+import com.kitfox.svg.SVGElement;
+import com.kitfox.svg.SVGException;
+import com.kitfox.svg.SVGRoot;
+import com.kitfox.svg.SVGUniverse;
+import com.kitfox.svg.Text;
+import com.kitfox.svg.Tspan;
+import com.kitfox.svg.animation.AnimationElement;
+
@RasterOutputWidget
public class SVGNode extends G2DNode implements InitValueSupport, LoaderNode {
-\r
- public static class SVGNodeAssignment {\r
- public String elementId;\r
- public String attributeNameOrId;\r
- public String value;\r
- public SVGNodeAssignment(String elementId, String attributeNameOrId, String value) {\r
- this.elementId = elementId;\r
- this.attributeNameOrId = attributeNameOrId;\r
- this.value = value;\r
- }\r
- @Override\r
- public int hashCode() {\r
- final int prime = 31;\r
- int result = 1;\r
- result = prime * result + ((attributeNameOrId == null) ? 0 : attributeNameOrId.hashCode());\r
- result = prime * result + ((elementId == null) ? 0 : elementId.hashCode());\r
- result = prime * result + ((value == null) ? 0 : value.hashCode());\r
- return result;\r
- }\r
- @Override\r
- public boolean equals(Object obj) {\r
- if (this == obj)\r
- return true;\r
- if (obj == null)\r
- return false;\r
- if (getClass() != obj.getClass())\r
- return false;\r
- SVGNodeAssignment other = (SVGNodeAssignment) obj;\r
- if (attributeNameOrId == null) {\r
- if (other.attributeNameOrId != null)\r
- return false;\r
- } else if (!attributeNameOrId.equals(other.attributeNameOrId))\r
- return false;\r
- if (elementId == null) {\r
- if (other.elementId != null)\r
- return false;\r
- } else if (!elementId.equals(other.elementId))\r
- return false;\r
- if (value == null) {\r
- if (other.value != null)\r
- return false;\r
- } else if (!value.equals(other.value))\r
- return false;\r
- return true;\r
- }\r
- }\r
-
- private static final long serialVersionUID = 8508750881358776559L;
-
- protected String data = null;\r
- protected String defaultData = null;\r
- protected Point targetSize = null;\r
- protected Boolean useMipMap = true;\r
- protected Rectangle2D bounds = null;\r
- \r
- protected List<SVGNodeAssignment> assignments = new ArrayList<SVGNodeAssignment>();\r
-\r
- transient BufferedImage buffer = null;\r
- transient String documentCache = null;\r
- transient SVGDiagram diagramCache = null;\r
- transient String dataHash = null;\r
-\r
- static transient Map<String, WeakReference<BufferedImage>> bufferCache = new HashMap<String, WeakReference<BufferedImage>>();\r
-\r
- @Override\r
- public void cleanup() {\r
- cleanDiagramCache();\r
- }\r
-\r
- public void setAssignments(List<SVGNodeAssignment> ass) {\r
- assignments.clear();\r
- assignments.addAll(ass);\r
- }\r
- \r
- public void cleanDiagramCache() {\r
- SVGDiagram d = diagramCache;\r
- if (d != null) {\r
- diagramCache = null;\r
- SVGUniverse univ = SVGCache.getSVGUniverse();\r
- if (univ.decRefCountAndClear(d.getXMLBase()) == 0) {\r
- // Cleared!\r
- //System.out.println("cleared: " + d.getXMLBase());\r
- }\r
- }\r
- }\r
-\r
- static WeakHashMap<String, String> dataCache = new WeakHashMap<String, String>();\r
-\r
+
+ private static final long serialVersionUID = 8508750881358776559L;
+
+ protected String data = null;
+ protected String defaultData = null;
+ protected Point targetSize = null;
+ protected Boolean useMipMap = true;
+ protected Rectangle2D bounds = null;
+
+ protected List<SVGNodeAssignment> assignments = new ArrayList<SVGNodeAssignment>();
+
+ protected transient BufferedImage buffer = null;
+ protected transient String documentCache = null;
+ protected transient SVGDiagram diagramCache = null;
+ protected transient String dataHash = null;
+
+ static transient Map<String, WeakReference<BufferedImage>> bufferCache = new HashMap<String, WeakReference<BufferedImage>>();
+
+ @Override
+ public void init() {
+ super.init();
+ }
+
+ @Override
+ public void cleanup() {
+ cleanDiagramCache();
+ }
+
+ public void setAssignments(List<SVGNodeAssignment> ass) {
+ assignments.clear();
+ assignments.addAll(ass);
+ }
+
+ public void cleanDiagramCache() {
+ SVGDiagram d = diagramCache;
+ if (d != null) {
+ diagramCache = null;
+ SVGUniverse univ = SVGCache.getSVGUniverse();
+ if (univ.decRefCountAndClear(d.getXMLBase()) == 0) {
+ // Cleared!
+ //System.out.println("cleared: " + d.getXMLBase());
+ }
+ }
+ }
+
+ static WeakHashMap<String, String> dataCache = new WeakHashMap<String, String>();
+
@PropertySetter("SVG")
@SyncField("data")
- public void setData(String data) {\r
- String cached = dataCache.get(data);\r
- if (cached == null) {\r
- cached = data;\r
- dataCache.put(data, data);\r
- }\r
- this.data = cached;\r
- this.defaultData = cached;\r
+ public void setData(String data) {
+ String cached = dataCache.get(data);
+ if (cached == null) {
+ cached = data;
+ dataCache.put(data, data);
+ }
+ this.data = cached;
+ this.defaultData = cached;
}
@SyncField("targetSize")
@SyncField("useMipMap")
public void useMipMap(Boolean use) {
this.useMipMap = use;
- }\r
-\r
+ }
+
@PropertySetter("Bounds")
@SyncField("bounds")
public void setBounds(Rectangle2D bounds) {
this.bounds = bounds;
}
- @Override\r
+ @Override
public Rectangle2D getBoundsInLocal() {
- if (bounds == null)\r
- parseSVG();\r
+ if (bounds == null)
+ parseSVG();
return bounds;
}
@Override
public void render(Graphics2D g2d) {
- if (data == null)\r
- return; // Not initialized\r
-\r
- if (!data.equals(documentCache) || diagramCache == null || buffer == null)\r
+ if (data == null)
+ return; // Not initialized
+
+ if (!data.equals(documentCache) || diagramCache == null || buffer == null)
initBuffer(g2d);
-\r
- AffineTransform ot = null;\r
- if (!transform.isIdentity()) {\r
- ot = g2d.getTransform();\r
- g2d.transform(transform);\r
+
+ AffineTransform ot = null;
+ if (!transform.isIdentity()) {
+ ot = g2d.getTransform();
+ g2d.transform(transform);
}
- if (buffer != null)\r
- buffer.paint(g2d);\r
-\r
- if (ot != null)\r
- g2d.setTransform(ot);\r
+ if (buffer != null)
+ buffer.paint(g2d);
+
+ if (ot != null)
+ g2d.setTransform(ot);
+ }
+
+ protected int dynamicHash() {
+ return 0;
}
protected String parseSVG() {
- if (data == null)\r
- return null;\r
-\r
- try {\r
- SVGUniverse univ = SVGCache.getSVGUniverse();\r
- synchronized(univ) {
- // NOTE: hard-coded to assume all SVG data is encoded in UTF-8\r
- byte[] dataBytes = data.getBytes("UTF-8");
- dataHash = digest(dataBytes, assignments);\r
- if (diagramCache != null)\r
- univ.decRefCount(diagramCache.getXMLBase());\r
- URI uri = univ.loadSVG(new ByteArrayInputStream(dataBytes), dataHash);
- diagramCache = univ.getDiagram(uri, false);\r
- if (diagramCache != null) {\r
- if (diagramCache.getRoot() == null) {\r
- diagramCache = univ.getDiagram(univ.loadSVG(BROKEN_SVG_DATA), false);\r
- dataHash = "broken";\r
- } else if (diagramCache.getRoot().getBoundingBox().isEmpty()) {\r
- diagramCache = univ.getDiagram(univ.loadSVG(EMPTY_SVG_DATA), false);\r
- dataHash = "empty";\r
- } else {\r
- for(SVGNodeAssignment ass : assignments) {\r
- SVGElement e = diagramCache.getElement(ass.elementId);\r
- if(e != null) {\r
- if("$text".equals(ass.attributeNameOrId)) {\r
- Tspan t = (Tspan)e;\r
- t.setText(ass.value);\r
- Text text = (Text)t.getParent();\r
- text.rebuild();\r
- } else {\r
- e.setAttribute(ass.attributeNameOrId, AnimationElement.AT_AUTO, ass.value);\r
- }\r
- }\r
- }\r
- if(!assignments.isEmpty())\r
- diagramCache.updateTime(0);\r
- }\r
- }
- documentCache = data;\r
- if (diagramCache != null) {\r
- setBounds((Rectangle2D) diagramCache.getRoot().getBoundingBox().clone());\r
- univ.incRefCount(diagramCache.getXMLBase());\r
- } else {\r
- setBounds(new Rectangle2D.Double());\r
- }\r
- }\r
- } catch (SVGException e) {\r
- setBounds((Rectangle2D) diagramCache.getViewRect().clone());\r
- } catch (IOException e) {\r
+ if (data == null)
+ return null;
+
+ SVGUniverse univ = SVGCache.getSVGUniverse();
+ try {
+ Rectangle2D bbox = null;
+ synchronized (univ) {
+ // Relinquish reference to current element
+ if (diagramCache != null) {
+ univ.decRefCount(diagramCache.getXMLBase());
+ diagramCache = null;
+ }
+
+ // Lets check for rootAssignment that contributes the whole SVG
+ SVGNodeAssignment rootAssignment = null;
+ if (!assignments.isEmpty()) {
+ for (SVGNodeAssignment ass : assignments) {
+ if (ass.attributeNameOrId.equals("$root")) {
+ rootAssignment = ass;
+ break;
+ }
+ }
+ }
+ byte[] dataBytes;
+ if (rootAssignment != null) {
+ dataBytes = rootAssignment.value.getBytes("UTF-8");
+ } else {
+ // NOTE: hard-coded to assume all SVG data is encoded in UTF-8
+ dataBytes = data.getBytes("UTF-8");
+ }
+ dataHash = digest(dataBytes, assignments, dynamicHash());
+ URI uri = univ.loadSVG(new ByteArrayInputStream(dataBytes), dataHash);
+ diagramCache = univ.getDiagram(uri, false);
+
+ if (diagramCache != null) {
+ univ.incRefCount(diagramCache.getXMLBase());
+ SVGRoot root = diagramCache.getRoot();
+ if (root == null) {
+ univ.decRefCount(diagramCache.getXMLBase());
+ diagramCache = univ.getDiagram(univ.loadSVG(BROKEN_SVG_DATA), false);
+ dataHash = "broken";
+ univ.incRefCount(diagramCache.getXMLBase());
+ bbox = (Rectangle2D) diagramCache.getRoot().getBoundingBox().clone();
+ } else {
+ bbox = root.getBoundingBox();
+ if (bbox.isEmpty()) {
+ // Lets check if this should be visible or not
+ Set<?> presentationAttributes = root.getPresentationAttributes();
+ if (!presentationAttributes.contains("display")) {
+ // TODO: fix this - How can one read values of attributes in SVG salamander???
+ univ.decRefCount(diagramCache.getXMLBase());
+ diagramCache = univ.getDiagram(univ.loadSVG(EMPTY_SVG_DATA), false);
+ dataHash = "empty";
+ univ.incRefCount(diagramCache.getXMLBase());
+ bbox = (Rectangle2D) root.getBoundingBox().clone();
+ } else {
+ bbox = new Rectangle2D.Double(0, 0, 0, 0);
+ }
+ } else {
+ if (applyAssignments(diagramCache, assignments)) {
+ bbox = (Rectangle2D) root.getBoundingBox().clone();
+ } else {
+ bbox = (Rectangle2D) bbox.clone();
+ }
+ }
+ }
+ } else {
+ bbox = new Rectangle2D.Double();
+ }
+ }
+
+ documentCache = data;
+ setBounds(bbox);
+ } catch (SVGException e) {
+ // This can only occur if diagramCache != null.
+ setBounds(diagramCache.getViewRect(new Rectangle2D.Double()));
+ univ.decRefCount(diagramCache.getXMLBase());
+ diagramCache = null;
+ } catch (IOException e) {
diagramCache = null;
}
return dataHash;
}
-\r
- public static Rectangle2D getBounds(String data) {\r
- return getBounds(data, null);\r
- }\r
-\r
- public static Rectangle2D getBounds(String data, List<SVGNodeAssignment> assignments) {\r
- if (data == null) {\r
- new Exception("null SVG data").printStackTrace();\r
- return null;\r
- }\r
-\r
- SVGDiagram diagramCache = null;\r
- try {\r
- // NOTE: hard-coded to assume all SVG data is encoded in UTF-8\r
- byte[] dataBytes = data.getBytes("UTF-8");\r
- String digest = digest(dataBytes, assignments);\r
-\r
- SVGUniverse univ = SVGCache.getSVGUniverse();\r
- // TODO: this completely removes any parallel processing from the SVG loading which would be nice to have.\r
- synchronized (univ) {\r
- //System.out.println(Thread.currentThread() + ": LOADING SVG: " + digest);\r
- URI uri = univ.loadSVG(new ByteArrayInputStream(dataBytes), digest);\r
- diagramCache = univ.getDiagram(uri, false);\r
- if (diagramCache != null) {\r
- if (diagramCache.getRoot() == null) {\r
- diagramCache = univ.getDiagram(univ.loadSVG(BROKEN_SVG_DATA));\r
- } else if (diagramCache.getRoot().getBoundingBox().isEmpty()) {\r
- diagramCache = univ.getDiagram(univ.loadSVG(EMPTY_SVG_DATA));\r
- }\r
- }\r
- }\r
-\r
- Rectangle2D rect = null;\r
- if (diagramCache != null) {\r
- SVGRoot root = diagramCache.getRoot();\r
- Rectangle2D bbox = root.getBoundingBox();\r
- rect = (Rectangle2D) bbox.clone();\r
- } else {\r
- rect = new Rectangle2D.Double();\r
- }\r
- return rect;\r
- } catch (SVGException e) {\r
- return ((Rectangle2D) diagramCache.getViewRect().clone());\r
- } catch(IOException e) {\r
- }\r
- return null;\r
- }\r
-\r
- public static Rectangle2D getRealBounds(String data) {\r
- return getRealBounds(data, null);\r
- }\r
-
- public static Rectangle2D getRealBounds(String data, List<SVGNodeAssignment> assignments) {\r
- if (data == null) {\r
- new Exception("null SVG data").printStackTrace();\r
- return null;\r
- }\r
-\r
- SVGDiagram diagramCache = null;\r
- try {\r
- // NOTE: hard-coded to assume all SVG data is encoded in UTF-8\r
- byte[] dataBytes = data.getBytes("UTF-8");\r
- String digest = digest(dataBytes, assignments);\r
-\r
- SVGUniverse univ = SVGCache.getSVGUniverse();\r
- // TODO: this completely removes any parallel processing from the SVG loading which would be nice to have.\r
- synchronized (univ) {\r
- //System.out.println(Thread.currentThread() + ": LOADING SVG: " + digest);\r
- URI uri = univ.loadSVG(new ByteArrayInputStream(dataBytes), digest);\r
- diagramCache = univ.getDiagram(uri, false);\r
- if (diagramCache != null) {\r
- SVGRoot root = diagramCache.getRoot(); \r
- if (root == null) return new Rectangle2D.Double();\r
- return (Rectangle2D)root.getBoundingBox().clone();\r
- }\r
- }\r
- } catch (SVGException e) {\r
- return ((Rectangle2D) diagramCache.getViewRect().clone());\r
- } catch(IOException e) {\r
- }\r
- return null;\r
- }\r
-\r
- protected void initBuffer(Graphics2D g2d) {\r
- \r
- if (!data.equals(documentCache) || diagramCache == null) {\r
- dataHash = parseSVG();
- if (diagramCache == null) {
- System.err.println("UNABLE TO PARSE SVG:\n" + data);
- return;
- }\r
+
+ protected boolean applyAssignments(SVGDiagram diagram, List<SVGNodeAssignment> assignments) throws SVGException {
+ if (assignments.isEmpty())
+ return false;
+
+ boolean changed = false;
+
+ for (SVGNodeAssignment ass : assignments) {
+ SVGElement e = diagram.getElement(ass.elementId);
+ if (e != null) {
+ if ("$text".equals(ass.attributeNameOrId)) {
+ if (e instanceof Tspan) {
+ Tspan t = (Tspan) e;
+ if (ass.value.trim().isEmpty()) {
+ t.setText("-");
+ } else {
+ t.setText(ass.value);
+ }
+ SVGElement parent = t.getParent();
+ if (parent instanceof Text)
+ ((Text) parent).rebuild();
+ changed = true;
+ }
+ } else if (ass.attributeNameOrId.startsWith("#")) {
+ e.setAttribute(ass.attributeNameOrId.substring(1), AnimationElement.AT_CSS, ass.value);
+ changed = true;
+ } else {
+ e.setAttribute(ass.attributeNameOrId, AnimationElement.AT_AUTO, ass.value);
+ changed = true;
+ }
+ }
+ }
+
+ return changed;
+ }
+
+ public static Rectangle2D getBounds(String data) {
+ return getBounds(data, 0);
+ }
+
+ public static Rectangle2D getBounds(String data, int dynamicHash) {
+ return getBounds(data, Collections.emptyList(), dynamicHash);
+ }
+
+ public static Rectangle2D getBounds(String data, List<SVGNodeAssignment> assignments, int dynamicHash) {
+ if (data == null) {
+ new Exception("null SVG data").printStackTrace();
+ return null;
+ }
+
+ SVGDiagram diagramCache = null;
+ try {
+ // NOTE: hard-coded to assume all SVG data is encoded in UTF-8
+ byte[] dataBytes = data.getBytes("UTF-8");
+ String digest = digest(dataBytes, assignments, dynamicHash);
+
+ SVGUniverse univ = SVGCache.getSVGUniverse();
+ // TODO: this completely removes any parallel processing from the SVG loading which would be nice to have.
+ synchronized (univ) {
+ //System.out.println(Thread.currentThread() + ": LOADING SVG: " + digest);
+ URI uri = univ.loadSVG(new ByteArrayInputStream(dataBytes), digest);
+ diagramCache = univ.getDiagram(uri, false);
+ if (diagramCache != null) {
+ if (diagramCache.getRoot() == null) {
+ diagramCache = univ.getDiagram(univ.loadSVG(BROKEN_SVG_DATA));
+ } else if (diagramCache.getRoot().getBoundingBox().isEmpty()) {
+ diagramCache = univ.getDiagram(univ.loadSVG(EMPTY_SVG_DATA));
+ }
+ }
+ }
+
+ Rectangle2D rect = null;
+ if (diagramCache != null) {
+ SVGRoot root = diagramCache.getRoot();
+ Rectangle2D bbox = root.getBoundingBox();
+ rect = (Rectangle2D) bbox.clone();
+ } else {
+ rect = new Rectangle2D.Double();
+ }
+ return rect;
+ } catch (SVGException e) {
+ return diagramCache.getViewRect(new Rectangle2D.Double());
+ } catch(IOException e) {
+ }
+ return null;
+ }
+
+ public static Rectangle2D getRealBounds(String data) {
+ return getRealBounds(data, Collections.emptyList(), 0);
+ }
+
+ public static Rectangle2D getRealBounds(String data, List<SVGNodeAssignment> assignments, int dynamicHash) {
+ if (data == null) {
+ new Exception("null SVG data").printStackTrace();
+ return null;
+ }
+
+ SVGDiagram diagramCache = null;
+ try {
+ // NOTE: hard-coded to assume all SVG data is encoded in UTF-8
+ byte[] dataBytes = data.getBytes("UTF-8");
+ String digest = digest(dataBytes, assignments, dynamicHash);
+
+ SVGUniverse univ = SVGCache.getSVGUniverse();
+ // TODO: this completely removes any parallel processing from the SVG loading which would be nice to have.
+ synchronized (univ) {
+ //System.out.println(Thread.currentThread() + ": LOADING SVG: " + digest);
+ URI uri = univ.loadSVG(new ByteArrayInputStream(dataBytes), digest);
+ diagramCache = univ.getDiagram(uri, false);
+ if (diagramCache != null) {
+ SVGRoot root = diagramCache.getRoot();
+ if (root == null) return new Rectangle2D.Double();
+ return (Rectangle2D)root.getBoundingBox().clone();
+ }
+ }
+ } catch (SVGException e) {
+ return diagramCache.getViewRect(new Rectangle2D.Double());
+ } catch(IOException e) {
+ }
+ return null;
+ }
+
+ protected void initBuffer(Graphics2D g2d) {
+ if (!data.equals(documentCache) || diagramCache == null) {
+ dataHash = parseSVG();
+ if (diagramCache == null) {
+ System.err.println("UNABLE TO PARSE SVG:\n" + data);
+ return;
+ }
}
if (buffer != null) {
buffer = bufferCache.get(dataHash).get();
} else if(diagramCache.getViewRect().getWidth()==0 || diagramCache.getViewRect().getHeight()==0) {
buffer = null;
- } else if(useMipMap) {\r
- if(G2DUtils.isAccelerated(g2d)) {
+ } else if(useMipMap) {
+ if(G2DUtils.isAccelerated(g2d)) {
buffer = new MipMapVRamBufferedImage(diagramCache, bounds, targetSize);
} else {
buffer = new MipMapBufferedImage(diagramCache, bounds, targetSize);
}
bufferCache.put(dataHash, new WeakReference<BufferedImage>(buffer));
} else {
- if(G2DUtils.isAccelerated(g2d)) {
+ if(G2DUtils.isAccelerated(g2d)) {
buffer = new VRamBufferedImage(diagramCache, bounds, targetSize);
} else {
buffer = new BufferedImage(diagramCache, bounds, targetSize);
bufferCache.put(dataHash, new WeakReference<BufferedImage>(buffer));
}
}
-\r
- public void setProperty(String field, Object value) {\r
- if("data".equals(field)) {\r
-// System.out.println("SVGNode data -> " + value);\r
- this.data = (String)value;\r
- } else if ("z".equals(field)) {\r
-// System.out.println("SVGNode z -> " + value);\r
- setZIndex((Integer)value);\r
- } else if ("position".equals(field)) {\r
-// System.out.println("SVGNode position -> " + value);\r
- Point point = (Point)value;\r
- setTransform(AffineTransform.getTranslateInstance(point.x, point.y));\r
-// setPosition(point.x, point.y);\r
- }\r
- }\r
-\r
- @Override\r
- public void initValues() {\r
- data = defaultData;\r
- dataHash = null;\r
- buffer = null;\r
- }\r
-\r
- static WeakHashMap<String, String> digestCache = new WeakHashMap<String, String>();\r
- \r
- static String digest(byte[] dataBytes, List<SVGNodeAssignment> assignments) {\r
- try {\r
- MessageDigest md = MessageDigest.getInstance("MD5");\r
- byte[] messageDigest = md.digest(dataBytes);\r
- BigInteger number = new BigInteger(1, messageDigest);\r
- String dataHash = number.toString(16) + (assignments != null ? assignments.hashCode() : 0);\r
- String result = digestCache.get(dataHash);\r
- if(result == null) {\r
- result = dataHash;\r
- digestCache.put(dataHash,dataHash);\r
- }\r
- return result;\r
- } catch (NoSuchAlgorithmException e) {\r
- // Shouldn't happen\r
- throw new Error("MD5 digest must exist.");\r
- }\r
- }\r
-\r
- static URL BROKEN_SVG_DATA = SVGNode.class.getResource("broken.svg");\r
- static URL EMPTY_SVG_DATA = SVGNode.class.getResource("empty.svg");\r
-\r
- @Override\r
- public Function1<Object, Boolean> getPropertyFunction(String propertyName) {\r
- return ScenegraphUtils.getMethodPropertyFunction(AWTThread.getThreadAccess(), this, propertyName);\r
- }\r
- \r
- @Override\r
- public <T> T getProperty(String propertyName) {\r
- return null;\r
- }\r
-\r
- @Override\r
- public void setPropertyCallback(Function2<String, Object, Boolean> callback) {\r
- }\r
-\r
- public void synchronizeDocument(String document) {\r
- setData(document);\r
- }\r
-\r
- public void synchronizeTransform(double[] data) {\r
- this.setTransform(new AffineTransform(data));\r
- }\r
+
+ public void setProperty(String field, Object value) {
+ if("data".equals(field)) {
+// System.out.println("SVGNode data -> " + value);
+ this.data = (String)value;
+ } else if ("z".equals(field)) {
+// System.out.println("SVGNode z -> " + value);
+ setZIndex((Integer)value);
+ } else if ("position".equals(field)) {
+// System.out.println("SVGNode position -> " + value);
+ Point point = (Point)value;
+ setTransform(AffineTransform.getTranslateInstance(point.x, point.y));
+// setPosition(point.x, point.y);
+ }
+ }
+
+ @Override
+ public void initValues() {
+ data = defaultData;
+ dataHash = null;
+ buffer = null;
+ }
+
+ static WeakHashMap<String, String> digestCache = new WeakHashMap<String, String>();
+
+ static String digest(byte[] dataBytes, List<SVGNodeAssignment> assignments, int dynamicHash) {
+ try {
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ byte[] messageDigest = md.digest(dataBytes);
+ BigInteger number = new BigInteger(1, messageDigest);
+ String dataHash = number.toString(16) + (assignments != null ? assignments.hashCode() : 0) + 31 * dynamicHash;
+ String result = digestCache.get(dataHash);
+ if(result == null) {
+ result = dataHash;
+ digestCache.put(dataHash,dataHash);
+ }
+ return result;
+ } catch (NoSuchAlgorithmException e) {
+ // Shouldn't happen
+ throw new Error("MD5 digest must exist.");
+ }
+ }
+
+ static URL BROKEN_SVG_DATA = SVGNode.class.getResource("broken.svg");
+ static URL EMPTY_SVG_DATA = SVGNode.class.getResource("empty.svg");
+
+ @Override
+ public Function1<Object, Boolean> getPropertyFunction(String propertyName) {
+ return ScenegraphUtils.getMethodPropertyFunction(AWTThread.getThreadAccess(), this, propertyName);
+ }
+ @Override
+ public <T> T getProperty(String propertyName) {
+ return null;
+ }
+
+ @Override
+ public void setPropertyCallback(Function2<String, Object, Boolean> callback) {
+ }
+
+ public void synchronizeDocument(String document) {
+ setData(document);
+ }
+
+ public void synchronizeTransform(double[] data) {
+ this.setTransform(new AffineTransform(data));
+ }
+
+ public String getSVGText() {
+ String ret = data.replace("<svg", "<g").replaceAll("svg>", "g>");
+ //return diagramCache.toString();
+ //return data.replace("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\"><svg xmlns=\"http://www.w3.org/2000/svg\" overflow=\"visible\" version=\"1.1\"", "<g").replaceAll("svg>", "/g>");
+ return ret;
+ }
+
+ public Rectangle2D getElementBounds(String id) throws SVGException {
+ SVGElement e = diagramCache.getElement(id);
+ if (e instanceof RenderableElement) {
+ return ((RenderableElement)e).getBoundingBox();
+ } else {
+ return null;
+ }
+ }
+
}