X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.scenegraph%2Fsrc%2Forg%2Fsimantics%2Fscenegraph%2Fg2d%2Fnodes%2FSVGNode.java;h=d21ba1f16a73c91ee9517244492bfa6e2dccec2e;hb=e1c5d8d7c5589cfa4a254e167f4d9f0e66df6bf7;hp=2dd285fd89d966387d6df759cb365af31740dca5;hpb=06ee0c4c71cd9e372969da1570e7fcac2c4397a5;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/SVGNode.java b/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/SVGNode.java index 2dd285fd8..d21ba1f16 100644 --- a/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/SVGNode.java +++ b/bundles/org.simantics.scenegraph/src/org/simantics/scenegraph/g2d/nodes/SVGNode.java @@ -24,9 +24,11 @@ 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; @@ -43,6 +45,7 @@ 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; @@ -56,69 +59,28 @@ import com.kitfox.svg.animation.AnimationElement; @RasterOutputWidget public class SVGNode extends G2DNode implements InitValueSupport, LoaderNode { - public static class SVGNodeAssignment { - public String elementId; - public String attributeNameOrId; - public String value; - public SVGNodeAssignment(String elementId, String attributeNameOrId, String value) { - this.elementId = elementId; - this.attributeNameOrId = attributeNameOrId; - this.value = value; - } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((attributeNameOrId == null) ? 0 : attributeNameOrId.hashCode()); - result = prime * result + ((elementId == null) ? 0 : elementId.hashCode()); - result = prime * result + ((value == null) ? 0 : value.hashCode()); - return result; - } - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - SVGNodeAssignment other = (SVGNodeAssignment) obj; - if (attributeNameOrId == null) { - if (other.attributeNameOrId != null) - return false; - } else if (!attributeNameOrId.equals(other.attributeNameOrId)) - return false; - if (elementId == null) { - if (other.elementId != null) - return false; - } else if (!elementId.equals(other.elementId)) - return false; - if (value == null) { - if (other.value != null) - return false; - } else if (!value.equals(other.value)) - return false; - return true; - } - } - - private static final long serialVersionUID = 8508750881358776559L; + 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 assignments = new ArrayList(); - transient BufferedImage buffer = null; - transient String documentCache = null; - transient SVGDiagram diagramCache = null; - transient String dataHash = null; + protected transient BufferedImage buffer = null; + protected transient String documentCache = null; + protected transient SVGDiagram diagramCache = null; + protected transient String dataHash = null; static transient Map> bufferCache = new HashMap>(); + @Override + public void init() { + super.init(); + } + @Override public void cleanup() { cleanDiagramCache(); @@ -204,6 +166,10 @@ public class SVGNode extends G2DNode implements InitValueSupport, LoaderNode { g2d.setTransform(ot); } + protected int dynamicHash() { + return 0; + } + protected String parseSVG() { if (data == null) return null; @@ -218,32 +184,54 @@ public class SVGNode extends G2DNode implements InitValueSupport, LoaderNode { diagramCache = null; } - // NOTE: hard-coded to assume all SVG data is encoded in UTF-8 - byte[] dataBytes = data.getBytes("UTF-8"); - dataHash = digest(dataBytes, assignments); + // 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()); - - if (diagramCache.getRoot() == null) { + 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 = diagramCache.getRoot().getBoundingBox(); + bbox = root.getBoundingBox(); if (bbox.isEmpty()) { - univ.decRefCount(diagramCache.getXMLBase()); - diagramCache = univ.getDiagram(univ.loadSVG(EMPTY_SVG_DATA), false); - dataHash = "empty"; - univ.incRefCount(diagramCache.getXMLBase()); - bbox = (Rectangle2D) diagramCache.getRoot().getBoundingBox().clone(); + // 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) diagramCache.getRoot().getBoundingBox().clone(); + bbox = (Rectangle2D) root.getBoundingBox().clone(); } else { bbox = (Rectangle2D) bbox.clone(); } @@ -268,10 +256,12 @@ public class SVGNode extends G2DNode implements InitValueSupport, LoaderNode { return dataHash; } - private static boolean applyAssignments(SVGDiagram diagram, List assignments) throws SVGException { + protected boolean applyAssignments(SVGDiagram diagram, List assignments) throws SVGException { if (assignments.isEmpty()) return false; + boolean changed = false; + for (SVGNodeAssignment ass : assignments) { SVGElement e = diagram.getElement(ass.elementId); if (e != null) { @@ -288,21 +278,28 @@ public class SVGNode extends G2DNode implements InitValueSupport, LoaderNode { ((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; } } } - diagram.updateTime(0); + return changed; } public static Rectangle2D getBounds(String data) { - return getBounds(data, null); + return getBounds(data, 0); } - public static Rectangle2D getBounds(String data, List assignments) { + public static Rectangle2D getBounds(String data, int dynamicHash) { + return getBounds(data, Collections.emptyList(), dynamicHash); + } + + public static Rectangle2D getBounds(String data, List assignments, int dynamicHash) { if (data == null) { new Exception("null SVG data").printStackTrace(); return null; @@ -312,7 +309,7 @@ public class SVGNode extends G2DNode implements InitValueSupport, LoaderNode { 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); + 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. @@ -346,10 +343,10 @@ public class SVGNode extends G2DNode implements InitValueSupport, LoaderNode { } public static Rectangle2D getRealBounds(String data) { - return getRealBounds(data, null); + return getRealBounds(data, Collections.emptyList(), 0); } - public static Rectangle2D getRealBounds(String data, List assignments) { + public static Rectangle2D getRealBounds(String data, List assignments, int dynamicHash) { if (data == null) { new Exception("null SVG data").printStackTrace(); return null; @@ -359,7 +356,7 @@ public class SVGNode extends G2DNode implements InitValueSupport, LoaderNode { 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); + 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. @@ -381,13 +378,12 @@ public class SVGNode extends G2DNode implements InitValueSupport, LoaderNode { } 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; - } + dataHash = parseSVG(); + if (diagramCache == null) { + System.err.println("UNABLE TO PARSE SVG:\n" + data); + return; + } } if (buffer != null) { @@ -399,14 +395,14 @@ public class SVGNode extends G2DNode implements InitValueSupport, LoaderNode { } else if(diagramCache.getViewRect().getWidth()==0 || diagramCache.getViewRect().getHeight()==0) { buffer = null; } else if(useMipMap) { - if(G2DUtils.isAccelerated(g2d)) { + if(G2DUtils.isAccelerated(g2d)) { buffer = new MipMapVRamBufferedImage(diagramCache, bounds, targetSize); } else { buffer = new MipMapBufferedImage(diagramCache, bounds, targetSize); } bufferCache.put(dataHash, new WeakReference(buffer)); } else { - if(G2DUtils.isAccelerated(g2d)) { + if(G2DUtils.isAccelerated(g2d)) { buffer = new VRamBufferedImage(diagramCache, bounds, targetSize); } else { buffer = new BufferedImage(diagramCache, bounds, targetSize); @@ -438,13 +434,13 @@ public class SVGNode extends G2DNode implements InitValueSupport, LoaderNode { } static WeakHashMap digestCache = new WeakHashMap(); - - static String digest(byte[] dataBytes, List assignments) { + + static String digest(byte[] dataBytes, List 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); + String dataHash = number.toString(16) + (assignments != null ? assignments.hashCode() : 0) + 31 * dynamicHash; String result = digestCache.get(dataHash); if(result == null) { result = dataHash; @@ -481,12 +477,21 @@ public class SVGNode extends G2DNode implements InitValueSupport, LoaderNode { public void synchronizeTransform(double[] data) { this.setTransform(new AffineTransform(data)); } - + public String getSVGText() { String ret = data.replace("", "g>"); //return diagramCache.toString(); //return data.replace("", "/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; + } + } + }