/* * #%L * org.gitools.ui.app * %% * Copyright (C) 2013 - 2014 Universitat Pompeu Fabra - Biomedical Genomics group * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/gpl-3.0.html>. * #L% */ /* =================================================== * JFreeSVG : an SVG library for the Java(tm) platform * =================================================== * * (C)opyright 2013, 2014, by Object Refinery Limited. All rights reserved. * * Project Info: http://www.jfree.org/jfreesvg/index.html * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. * Other names may be trademarks of their respective owners.] * * If you do not wish to be bound by the terms of the AGPL, an alternative * commercial license can be purchased. For details, please see visit the * JFreeSVG home page: * * http://www.jfree.org/jfreesvg */ package org.gitools.ui.app.svg.jfreesvg; import java.awt.*; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; /** * Defines the rendering hints that can be used with the {@link SVGGraphics2D} * class. The supported hints are:<br> * <ul> * <li>{@link #KEY_IMAGE_HANDLING} that controls how images are handled * (embedded in the SVG, or referenced externally);</li> * <li>{@link #KEY_IMAGE_HREF} that allows the caller to specify the image * href attribute for the next image;</li> * <li>{@link #KEY_TEXT_RENDERING} that allows configuration of the preferred * value of the SVG <code>text-rendering</code> attribute in text elements;</li> * <li>{@link #KEY_ELEMENT_ID} that allows the caller to specify the element * ID for the next element;</li> * <li>{@link #KEY_BEGIN_GROUP} tells the <code>SVGGraphics2D</code> instance * to start a new group element with an id equal to the hint value (which must * be an instance of String). Any other <code>Graphics2D</code> implementation * will ignore this hint;</li> * <li>{@link #KEY_END_GROUP} tells the <code>SVGGraphics2D</code> instance * to end a group element. The hint value is ignored. The caller assumes * responsibility for balancing the number of <code>KEY_BEGIN_GROUP</code> and * <code>KEY_END_GROUP</code> hints. Any other <code>Graphics2D</code> * implementation will ignore this hint.</li> * </ul> * */ public final class SVGHints { private SVGHints() { // no need to instantiate this } /** * The key for the hint that controls whether images are embedded in the * SVG or referenced externally. Valid hint values are * {@link #VALUE_IMAGE_HANDLING_EMBED} and * {@link #VALUE_IMAGE_HANDLING_REFERENCE}. */ public static final SVGHints.Key KEY_IMAGE_HANDLING = new SVGHints.Key(0); /** * Hint value for <code>KEY_IMAGE_HANDLING</code> to specify that images * should be embedded in the SVG output using PNG data <code>Base64</code> * encoded. */ public static final Object VALUE_IMAGE_HANDLING_EMBED = "VALUE_IMAGE_HANDLING_EMBED"; /** * Hint value for <code>KEY_IMAGE_HANDLING</code> to say that images should * be referenced externally. */ public static final Object VALUE_IMAGE_HANDLING_REFERENCE = "VALUE_IMAGE_HANDLING_REFERENCE"; /** * The key for a hint that permits configuration of the <a * href="https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-rendering">text-rendering * attribute</a> in SVG text elements */ public static final SVGHints.Key KEY_TEXT_RENDERING = new SVGHints.Key(1); /** * Hint value for <code>KEY_TEXT_RENDERING</code> to set the * <code>text-rendering</code> attribute in SVG text elements to 'auto'. */ public static final String VALUE_TEXT_RENDERING_AUTO = "auto"; /** * Hint value for <code>KEY_TEXT_RENDERING</code> to set the * <code>text-rendering</code> attribute in SVG text elements to * 'optimizeSpeed'. */ public static final String VALUE_TEXT_RENDERING_SPEED = "optimizeSpeed"; /** * Hint value for <code>KEY_TEXT_RENDERING</code> to set the * <code>text-rendering</code> attribute in SVG text elements to * 'optimizeLegibility'. */ public static final String VALUE_TEXT_RENDERING_LEGIBILITY = "optimizeLegibility"; /** * Hint value for <code>KEY_TEXT_RENDERING</code> to set the * <code>text-rendering</code> attribute in SVG text elements to * 'geometricPrecision'. */ public static final String VALUE_TEXT_RENDERING_PRECISION = "geometricPrecision"; /** * Hint value for <code>KEY_TEXT_RENDERING</code> to set the * <code>text-rendering</code> attribute in SVG text elements to * 'inherit'. */ public static final String VALUE_TEXT_RENDERING_INHERIT = "inherit"; /** * Hint key to supply string to be used as the href for an image that is * referenced rather than embedded. The value associated with the key * should be a string and will be used for the next image element written * to the SVG output (and then the hint will be cleared). * * @since 1.5 */ public static final SVGHints.Key KEY_IMAGE_HREF = new SVGHints.Key(2); /** * Hint key to supply an element id for the next element generated. * * @since 1.5 */ public static final SVGHints.Key KEY_ELEMENT_ID = new SVGHints.Key(3); /** * Hint key that informs the <code>SVGGraphics2D</code> that the caller * would like to begin a new group element. The hint value is the id for * the new group. After opening the new group the hint is cleared and it * is the caller's responsibility to close the group later using * {@link SVGHints#KEY_END_GROUP}. Groups can be nested. * * @since 1.7 */ public static final SVGHints.Key KEY_BEGIN_GROUP = new SVGHints.Key(4); /** * Hint key that informs the <code>SVGGraphics2D</code> that the caller * would like to close a previously opened group element. The hint * value is ignored. * * @since 1.7 */ public static final SVGHints.Key KEY_END_GROUP = new SVGHints.Key(5); /** * Hint key that informs the <code>SVGGraphics2D</code> that the caller * would like to add a title element to the output (with the hint value * being a string containing the title text). * * @since 1.9 */ public static final SVGHints.Key KEY_ELEMENT_TITLE = new SVGHints.Key(6); /** * A list of keys that are treated as synonyms for KEY_BEGIN_GROUP * (the list does not include KEY_BEGIN_GROUP itself). */ private static final List<RenderingHints.Key> beginGroupKeys; /** * A list of keys that are treated as synonyms for KEY_END_GROUP * (the list does not include KEY_END_GROUP itself). */ private static final List<RenderingHints.Key> endGroupKeys; /** * A list of keys that are treated as synonyms for KEY_ELEMENT_TITLE * (the list does not include KEY_ELEMENT_TITLE itself). */ private static final List<RenderingHints.Key> elementTitleKeys; static { beginGroupKeys = new ArrayList<RenderingHints.Key>(); endGroupKeys = new ArrayList<RenderingHints.Key>(); elementTitleKeys = new ArrayList<RenderingHints.Key>(); if (isOrsonChartsOnClasspath()) { beginGroupKeys.add(getOrsonChartsBeginElementKey()); endGroupKeys.add(getOrsonChartsEndElementKey()); elementTitleKeys.add(getOrsonChartsElementTitleKey()); } } /** * Creates and returns a list of keys that are synonymous with * {@link #KEY_BEGIN_GROUP}. * * @return A list (never <code>null</code>). * * @since 1.8 */ public static List<RenderingHints.Key> getBeginGroupKeys() { return new ArrayList<RenderingHints.Key>(beginGroupKeys); } /** * Adds a key to the list of keys that are synonyms for * {@link SVGHints#KEY_BEGIN_GROUP}. * * @param key the key (<code>null</code> not permitted). * * @since 1.8 */ public static void addBeginGroupKey(RenderingHints.Key key) { beginGroupKeys.add(key); } /** * Removes a key from the list of keys that are synonyms for * {@link SVGHints#KEY_BEGIN_GROUP}. * * @param key the key (<code>null</code> not permitted). * * @since 1.8 */ public static void removeBeginGroupKey(RenderingHints.Key key) { beginGroupKeys.remove(key); } /** * Clears the list of keys that are treated as synonyms for * {@link SVGHints#KEY_BEGIN_GROUP}. * * @since 1.8 */ public static void clearBeginGroupKeys() { beginGroupKeys.clear(); } /** * Returns <code>true</code> if this key is equivalent to * {@link #KEY_BEGIN_GROUP}, and <code>false</code> otherwise. The purpose * of this method is to allow certain keys from external packages (such as * Orson Charts) to use their own keys to drive the behaviour of * SVGHints.KEY_BEGIN_GROUP. This has two benefits: (1) it avoids the * necessity to make JFreeSVG a direct dependency, and (2) it makes the * grouping behaviour generic from the point of view of the external * package, rather than SVG-specific. * * @param key the key (<code>null</code> not permitted) * * @return A boolean. * * @since 1.8 */ public static boolean isBeginGroupKey(RenderingHints.Key key) { return SVGHints.KEY_BEGIN_GROUP.equals(key) || beginGroupKeys.contains(key); } /** * Creates and returns a list of keys that are synonymous with * {@link #KEY_END_GROUP}. * * @return A list (never <code>null</code>). * * @since 1.8 */ public static List<RenderingHints.Key> getEndGroupKeys() { return new ArrayList<RenderingHints.Key>(endGroupKeys); } /** * Adds a key to the list of keys that are synonyms for * {@link SVGHints#KEY_END_GROUP}. * * @param key the key (<code>null</code> not permitted). * * @since 1.8 */ public static void addEndGroupKey(RenderingHints.Key key) { endGroupKeys.add(key); } /** * Removes a key from the list of keys that are synonyms for * {@link SVGHints#KEY_END_GROUP}. * * @param key the key (<code>null</code> not permitted). * * @since 1.8 */ public static void removeEndGroupKey(RenderingHints.Key key) { endGroupKeys.remove(key); } /** * Clears the list of keys that are treated as synonyms for * {@link SVGHints#KEY_END_GROUP}. * * @since 1.8 */ public static void clearEndGroupKeys() { endGroupKeys.clear(); } /** * Returns <code>true</code> if this key is equivalent to * {@link #KEY_END_GROUP}, and <code>false</code> otherwise. The purpose * of this method is to allow certain keys from external packages (such as * Orson Charts) to use their own keys to drive the behaviour of * SVGHints.KEY_END_GROUP. This has two benefits: (1) it avoids the * necessity to make JFreeSVG a direct dependency, and (2) it makes the * grouping behaviour generic from the point of view of the external * package, rather than SVG-specific. * * @param key the key (<code>null</code> not permitted) * * @return A boolean. * * @since 1.8 */ public static boolean isEndGroupKey(RenderingHints.Key key) { return SVGHints.KEY_END_GROUP.equals(key) || endGroupKeys.contains(key); } /** * Creates and returns a list of keys that are synonymous with * {@link #KEY_ELEMENT_TITLE}. * * @return A list (never <code>null</code>). * * @since 1.9 */ public static List<RenderingHints.Key> getElementTitleKeys() { return new ArrayList<RenderingHints.Key>(elementTitleKeys); } /** * Adds a key to the list of keys that are synonyms for * {@link SVGHints#KEY_ELEMENT_TITLE}. * * @param key the key (<code>null</code> not permitted). * * @since 1.9 */ public static void addElementTitleKey(RenderingHints.Key key) { elementTitleKeys.add(key); } /** * Removes a key from the list of keys that are synonyms for * {@link SVGHints#KEY_ELEMENT_TITLE}. * * @param key the key (<code>null</code> not permitted). * * @since 1.9 */ public static void removeElementTitleKey(RenderingHints.Key key) { elementTitleKeys.remove(key); } /** * Clears the list of keys that are treated as synonyms for * {@link SVGHints#KEY_ELEMENT_TITLE}. * * @since 1.9 */ public static void clearElementTitleKeys() { elementTitleKeys.clear(); } /** * Returns <code>true</code> if this key is equivalent to * {@link #KEY_ELEMENT_TITLE}, and <code>false</code> otherwise. The * purpose of this method is to allow certain keys from external packages * (such as Orson Charts) to use their own keys to drive the behaviour of * SVGHints.KEY_ELEMENT_TITLE. This has two benefits: (1) it avoids the * necessity to make JFreeSVG a direct dependency, and (2) it makes the * element title behaviour generic from the point of view of the external * package, rather than SVG-specific. * * @param key the key (<code>null</code> not permitted) * * @return A boolean. * * @since 1.9 */ public static boolean isElementTitleKey(RenderingHints.Key key) { return SVGHints.KEY_ELEMENT_TITLE.equals(key) || elementTitleKeys.contains(key); } /** * Returns <code>true</code> if Orson Charts (version 1.3 or later) is on * the classpath, and <code>false</code> otherwise. This method is used to * auto-register keys from Orson Charts that should translate to the * behaviour of {@link SVGHints#KEY_BEGIN_GROUP} and * {@link SVGHints#KEY_END_GROUP}. * <br><br> * The Orson Charts library can be found at * http://www.object-refinery.com/orsoncharts/ * * @return A boolean. * * @since 1.8 */ private static boolean isOrsonChartsOnClasspath() { return (getOrsonChartsBeginElementKey() != null); } private static RenderingHints.Key getOrsonChartsBeginElementKey() { Class<?> renderingHintsClass; try { renderingHintsClass = Class.forName("com.orsoncharts.Chart3DHints"); Field f = renderingHintsClass.getDeclaredField("KEY_BEGIN_ELEMENT"); return (RenderingHints.Key) f.get(null); } catch (ClassNotFoundException e) { return null; } catch (NoSuchFieldException ex) { return null; } catch (SecurityException ex) { return null; } catch (IllegalArgumentException ex) { return null; } catch (IllegalAccessException ex) { return null; } } private static RenderingHints.Key getOrsonChartsEndElementKey() { Class<?> renderingHintsClass; try { renderingHintsClass = Class.forName("com.orsoncharts.Chart3DHints"); Field f = renderingHintsClass.getDeclaredField("KEY_END_ELEMENT"); return (RenderingHints.Key) f.get(null); } catch (ClassNotFoundException e) { return null; } catch (NoSuchFieldException ex) { return null; } catch (SecurityException ex) { return null; } catch (IllegalArgumentException ex) { return null; } catch (IllegalAccessException ex) { return null; } } private static RenderingHints.Key getOrsonChartsElementTitleKey() { Class<?> renderingHintsClass; try { renderingHintsClass = Class.forName("com.orsoncharts.Chart3DHints"); Field f = renderingHintsClass.getDeclaredField("KEY_ELEMENT_TITLE"); return (RenderingHints.Key) f.get(null); } catch (ClassNotFoundException e) { return null; } catch (NoSuchFieldException ex) { return null; } catch (SecurityException ex) { return null; } catch (IllegalArgumentException ex) { return null; } catch (IllegalAccessException ex) { return null; } } /** * A key for hints used by the {@link SVGGraphics2D} class. */ public static class Key extends RenderingHints.Key { /** * Creates a new instance. * * @param privateKey the private key. */ public Key(int privateKey) { super(privateKey); } /** * Returns <code>true</code> if <code>val</code> is a value that is * compatible with this key, and <code>false</code> otherwise. * * @param val the value. * * @return A boolean. */ @Override public boolean isCompatibleValue(Object val) { switch (intKey()) { case 0: return VALUE_IMAGE_HANDLING_EMBED.equals(val) || VALUE_IMAGE_HANDLING_REFERENCE.equals(val); case 1: return VALUE_TEXT_RENDERING_AUTO.equals(val) || VALUE_TEXT_RENDERING_INHERIT.equals(val) || VALUE_TEXT_RENDERING_LEGIBILITY.equals(val) || VALUE_TEXT_RENDERING_PRECISION.equals(val) || VALUE_TEXT_RENDERING_SPEED.equals(val); case 2: // KEY_IMAGE:URL return val == null || val instanceof String; case 3: // KEY_ELEMENT_ID return val == null || val instanceof String; case 4: // KEY_BEGIN_GROUP return val == null || val instanceof String; case 5: // KEY_END_GROUP return true; // the value is ignored case 6: // KEY_ELEMENT_TITLE return val instanceof String; default: throw new RuntimeException("Not possible!"); } } } }