/* * SVG Salamander * Copyright (c) 2004, Mark McKay * All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * * Mark McKay can be contacted at mark@kitfox.com. Salamander and other * projects can be found at http://www.kitfox.com * * Created on January 26, 2004, 3:25 AM */ package com.kitfox.svg; import java.awt.Color; import java.awt.geom.AffineTransform; import java.net.URI; import java.util.ArrayList; import java.util.Iterator; import java.util.logging.Level; import java.util.logging.Logger; import com.kitfox.svg.xml.StyleAttribute; /** * @author Mark McKay * @author <a href="mailto:mark@kitfox.com">Mark McKay</a> */ abstract public class Gradient extends FillElement { public static final String TAG_NAME = "gradient"; public static final int SM_PAD = 0; public static final int SM_REPEAT = 1; public static final int SM_REFLECT = 2; int spreadMethod = SM_PAD; public static final int GU_OBJECT_BOUNDING_BOX = 0; public static final int GU_USER_SPACE_ON_USE = 1; protected int gradientUnits = GU_OBJECT_BOUNDING_BOX; // Either this gradient contains a list of stops, or it will take it's // stops from the referenced gradient ArrayList stops = new ArrayList(); URI stopRef = null; protected AffineTransform gradientTransform = null; // Cache arrays of stop values here float[] stopFractions; Color[] stopColors; /** * Creates a new instance of Gradient */ public Gradient() { } @Override public String getTagName() { return TAG_NAME; } /** * Called after the start element but before the end element to indicate * each child tag that has been processed */ @Override public void loaderAddChild(SVGLoaderHelper helper, SVGElement child) throws SVGElementException { super.loaderAddChild(helper, child); if (!(child instanceof Stop)) { return; } appendStop((Stop) child); } @Override protected void build() throws SVGException { super.build(); StyleAttribute sty = new StyleAttribute(); String strn; if (getPres(sty.setName("spreadMethod"))) { strn = sty.getStringValue().toLowerCase(); if (strn.equals("repeat")) { spreadMethod = SM_REPEAT; } else if (strn.equals("reflect")) { spreadMethod = SM_REFLECT; } else { spreadMethod = SM_PAD; } } if (getPres(sty.setName("gradientUnits"))) { strn = sty.getStringValue().toLowerCase(); if (strn.equals("userspaceonuse")) { gradientUnits = GU_USER_SPACE_ON_USE; } else { gradientUnits = GU_OBJECT_BOUNDING_BOX; } } if (getPres(sty.setName("gradientTransform"))) { gradientTransform = parseTransform(sty.getStringValue()); } // If we still don't have one, set it to identity if (gradientTransform == null) { gradientTransform = new AffineTransform(); } // Check to see if we're using our own stops or referencing someone // else's if (getPres(sty.setName("xlink:href"))) { try { stopRef = sty.getURIValue(getXMLBase()); // System.err.println("Gradient: " + sty.getStringValue() + ", " // + getXMLBase() + ", " + src); // URI src = getXMLBase().resolve(href); // stopRef = (Gradient)diagram.getUniverse().getElement(src); } catch (Exception e) { throw new SVGException( "Could not resolve relative URL in Gradient: " + sty.getStringValue() + ", " + getXMLBase(), e); } } } public float[] getStopFractions() { if (stopRef != null) { Gradient grad = (Gradient) diagram.getUniverse() .getElement(stopRef); return grad.getStopFractions(); } if (stopFractions != null) { return stopFractions; } stopFractions = new float[stops.size()]; int idx = 0; for (Iterator it = stops.iterator(); it.hasNext();) { Stop stop = (Stop) it.next(); float val = stop.offset; if (idx != 0 && val < stopFractions[idx - 1]) { val = stopFractions[idx - 1]; } stopFractions[idx++] = val; } return stopFractions; } public Color[] getStopColors() { if (stopRef != null) { Gradient grad = (Gradient) diagram.getUniverse() .getElement(stopRef); return grad.getStopColors(); } if (stopColors != null) { return stopColors; } stopColors = new Color[stops.size()]; int idx = 0; for (Iterator it = stops.iterator(); it.hasNext();) { Stop stop = (Stop) it.next(); int stopColorVal = stop.color.getRGB(); Color stopColor = new Color((stopColorVal >> 16) & 0xff, (stopColorVal >> 8) & 0xff, stopColorVal & 0xff, clamp((int) (stop.opacity * 255), 0, 255)); stopColors[idx++] = stopColor; } return stopColors; } public void setStops(Color[] colors, float[] fractions) { if (colors.length != fractions.length) { throw new IllegalArgumentException(); } this.stopColors = colors; this.stopFractions = fractions; stopRef = null; } private static int clamp(int val, int min, int max) { if (val < min) { return min; } if (val > max) { return max; } return val; } public void setStopRef(URI grad) { stopRef = grad; } public void appendStop(Stop stop) { stops.add(stop); } /** * Updates all attributes in this diagram associated with a time event. Ie, * all attributes with track information. * * @return - true if this node has changed state as a result of the time * update */ @Override public boolean updateTime(double curTime) throws SVGException { // if (trackManager.getNumTracks() == 0) return false; boolean stateChange = false; // Get current values for parameters StyleAttribute sty = new StyleAttribute(); String strn; if (getPres(sty.setName("spreadMethod"))) { int newVal; strn = sty.getStringValue().toLowerCase(); if (strn.equals("repeat")) { newVal = SM_REPEAT; } else if (strn.equals("reflect")) { newVal = SM_REFLECT; } else { newVal = SM_PAD; } if (spreadMethod != newVal) { spreadMethod = newVal; stateChange = true; } } if (getPres(sty.setName("gradientUnits"))) { int newVal; strn = sty.getStringValue().toLowerCase(); if (strn.equals("userspaceonuse")) { newVal = GU_USER_SPACE_ON_USE; } else { newVal = GU_OBJECT_BOUNDING_BOX; } if (newVal != gradientUnits) { gradientUnits = newVal; stateChange = true; } } if (getPres(sty.setName("gradientTransform"))) { AffineTransform newVal = parseTransform(sty.getStringValue()); if (newVal != null && newVal.equals(gradientTransform)) { gradientTransform = newVal; stateChange = true; } } // Check to see if we're using our own stops or referencing someone // else's if (getPres(sty.setName("xlink:href"))) { try { URI newVal = sty.getURIValue(getXMLBase()); if ((newVal == null && stopRef != null) || (newVal != null && !newVal.equals(stopRef))) { stopRef = newVal; stateChange = true; } } catch (Exception e) { Logger.getLogger(SVGConst.SVG_LOGGER).log(Level.WARNING, "Could not parse xlink:href", e); } } // Check stops, if any for (Iterator it = stops.iterator(); it.hasNext();) { Stop stop = (Stop) it.next(); if (stop.updateTime(curTime)) { stateChange = true; stopFractions = null; stopColors = null; } } return stateChange; } }