-\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
+
+ private static DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ static {
+ dbf.setValidating(false);
+ try {
+ dbf.setFeature("http://xml.org/sax/features/namespaces", false);
+ dbf.setFeature("http://xml.org/sax/features/validation", false);
+ dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
+ dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+ } catch (ParserConfigurationException e) {
+ // Nothing to do
+ }
+ }
+
+ // Notice: Remember to change both implementations of applyAssigments when modifying the functionality.
+ protected static String applyAssigments(String svg, List<SVGNodeAssignment> assignments) {
+ try {
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ Document doc = db.parse(new InputSource(new StringReader(svg)));
+
+ NodeList entries = doc.getElementsByTagName("*");
+ for (int i=0; i<entries.getLength(); i++) {
+ Element element = (Element) entries.item(i);
+ if (element.hasAttribute("id")) {
+ element.setIdAttribute("id", true);
+ }
+ }
+ for (SVGNodeAssignment ass : assignments) {
+ Element e = doc.getElementById(ass.elementId);
+ if (e != null) {
+ if ("$text".equals(ass.attributeNameOrId)) {
+ if (e.getTagName().equals("tspan")) {
+ if (ass.value.trim().isEmpty()) {
+ e.setTextContent("-");
+ } else {
+ e.setTextContent(ass.value);
+ }
+ }
+ } else if (ass.attributeNameOrId.startsWith("#")) {
+ e.setAttribute(ass.attributeNameOrId.substring(1), ass.value);
+ } else {
+ e.setAttribute(ass.attributeNameOrId, ass.value);
+ }
+ } else {
+ LOGGER.warn("Element with id='" + ass.elementId + " was not found.");
+ }
+ }
+
+ DOMSource domSource = new DOMSource(doc);
+ StringWriter writer = new StringWriter();
+ StreamResult result = new StreamResult(writer);
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Transformer transformer = tf.newTransformer();
+ transformer.transform(domSource, result);
+ return writer.toString();
+
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ // Notice: Remember to change both implementations of applyAssigments when modifying the functionality.
+ protected boolean applyAssignments(SVGDiagram diagram, List<SVGNodeAssignment> assignments) throws SVGException {
+ if (assignments.isEmpty())
+ return false;
+
+ boolean changed = false;
+
+ // Without this elements are sometimes not found by id!
+ diagram.updateTime(0);
+
+ 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;
+ }
+ }
+ }
+
+ // Without this the attribute values are not correctly reflected in rendering
+ diagram.updateTime(0);
+
+ 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) {
+ LOGGER.warn("UNABLE TO PARSE SVG:\n" + data);
+ return;
+ }