/*

   Licensed to the Apache Software Foundation (ASF) under one or more
   contributor license agreements.  See the NOTICE file distributed with
   this work for additional information regarding copyright ownership.
   The ASF licenses this file to You under the Apache License, Version 2.0
   (the "License"); you may not use this file except in compliance with
   the License.  You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.

 */
package org.apache.batik.bridge;

import java.awt.Color;
import java.awt.Paint;
import java.awt.geom.AffineTransform;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.apache.batik.dom.util.XLinkSupport;
import org.apache.batik.ext.awt.MultipleGradientPaint;
import org.apache.batik.gvt.GraphicsNode;
import org.apache.batik.util.ParsedURL;

import org.w3c.dom.Element;
import org.w3c.dom.Node;

Bridge class for vending gradients.
Author:Thierry Kormann
Version:$Id: AbstractSVGGradientElementBridge.java 1831635 2018-05-15 13:33:47Z ssteiner $
/** * Bridge class for vending gradients. * * @author <a href="mailto:tkormann@apache.org">Thierry Kormann</a> * @version $Id: AbstractSVGGradientElementBridge.java 1831635 2018-05-15 13:33:47Z ssteiner $ */
public abstract class AbstractSVGGradientElementBridge extends AnimatableGenericSVGBridge implements PaintBridge, ErrorConstants {
Constructs a new AbstractSVGGradientElementBridge.
/** * Constructs a new AbstractSVGGradientElementBridge. */
protected AbstractSVGGradientElementBridge() {}
Creates a Paint according to the specified parameters.
Params:
  • ctx – the bridge context to use
  • paintElement – the element that defines a Paint
  • paintedElement – the element referencing the paint
  • paintedNode – the graphics node on which the Paint will be applied
  • opacity – the opacity of the Paint to create
/** * Creates a <code>Paint</code> according to the specified parameters. * * @param ctx the bridge context to use * @param paintElement the element that defines a Paint * @param paintedElement the element referencing the paint * @param paintedNode the graphics node on which the Paint will be applied * @param opacity the opacity of the Paint to create */
public Paint createPaint(BridgeContext ctx, Element paintElement, Element paintedElement, GraphicsNode paintedNode, float opacity) { String s; // stop elements List stops = extractStop(paintElement, opacity, ctx); // if no stops are defined, painting is the same as 'none' if (stops == null) { return null; } int stopLength = stops.size(); // if one stops is defined, painting is the same as a single color if (stopLength == 1) { return ((Stop)stops.get(0)).color; } float [] offsets = new float[stopLength]; Color [] colors = new Color[stopLength]; Iterator iter = stops.iterator(); for (int i=0; iter.hasNext(); ++i) { Stop stop = (Stop)iter.next(); offsets[i] = stop.offset; colors[i] = stop.color; } // 'spreadMethod' attribute - default is pad MultipleGradientPaint.CycleMethodEnum spreadMethod = MultipleGradientPaint.NO_CYCLE; s = SVGUtilities.getChainableAttributeNS (paintElement, null, SVG_SPREAD_METHOD_ATTRIBUTE, ctx); if (s.length() != 0) { spreadMethod = convertSpreadMethod(paintElement, s, ctx); } // 'color-interpolation' CSS property MultipleGradientPaint.ColorSpaceEnum colorSpace = CSSUtilities.convertColorInterpolation(paintElement); // 'gradientTransform' attribute - default is an Identity matrix AffineTransform transform; s = SVGUtilities.getChainableAttributeNS (paintElement, null, SVG_GRADIENT_TRANSFORM_ATTRIBUTE, ctx); if (s.length() != 0) { transform = SVGUtilities.convertTransform (paintElement, SVG_GRADIENT_TRANSFORM_ATTRIBUTE, s, ctx); } else { transform = new AffineTransform(); } Paint paint = buildGradient(paintElement, paintedElement, paintedNode, spreadMethod, colorSpace, transform, colors, offsets, ctx); return paint; }
Builds a concrete gradient according to the specified parameters.
Params:
  • paintElement – the element that defines a Paint
  • paintedElement – the element referencing the paint
  • paintedNode – the graphics node on which the Paint will be applied
  • spreadMethod – the spread method
  • colorSpace – the color space (sRGB | LinearRGB)
  • transform – the gradient transform
  • colors – the colors of the gradient
  • offsets – the offsets
  • ctx – the bridge context to use
/** * Builds a concrete gradient according to the specified parameters. * * @param paintElement the element that defines a Paint * @param paintedElement the element referencing the paint * @param paintedNode the graphics node on which the Paint will be applied * @param spreadMethod the spread method * @param colorSpace the color space (sRGB | LinearRGB) * @param transform the gradient transform * @param colors the colors of the gradient * @param offsets the offsets * @param ctx the bridge context to use */
protected abstract Paint buildGradient(Element paintElement, Element paintedElement, GraphicsNode paintedNode, MultipleGradientPaint.CycleMethodEnum spreadMethod, MultipleGradientPaint.ColorSpaceEnum colorSpace, AffineTransform transform, Color [] colors, float [] offsets, BridgeContext ctx); // convenient methods
Converts the spreadMethod attribute.
Params:
  • paintElement – the paint Element with a spreadMethod
  • s – the spread method
  • ctx – the BridgeContext to use for error information
/** * Converts the spreadMethod attribute. * * @param paintElement the paint Element with a spreadMethod * @param s the spread method * @param ctx the BridgeContext to use for error information */
protected static MultipleGradientPaint.CycleMethodEnum convertSpreadMethod (Element paintElement, String s, BridgeContext ctx) { if (SVG_REPEAT_VALUE.equals(s)) { return MultipleGradientPaint.REPEAT; } if (SVG_REFLECT_VALUE.equals(s)) { return MultipleGradientPaint.REFLECT; } if (SVG_PAD_VALUE.equals(s)) { return MultipleGradientPaint.NO_CYCLE; } throw new BridgeException (ctx, paintElement, ERR_ATTRIBUTE_VALUE_MALFORMED, new Object[] {SVG_SPREAD_METHOD_ATTRIBUTE, s}); }
Returns the stops elements of the specified gradient element. Stops can be children of the gradients or defined on one of its 'ancestor' (linked with the xlink:href attribute).
Params:
  • paintElement – the gradient element
  • opacity – the opacity
  • ctx – the bridge context to use
/** * Returns the stops elements of the specified gradient * element. Stops can be children of the gradients or defined on * one of its 'ancestor' (linked with the xlink:href attribute). * * @param paintElement the gradient element * @param opacity the opacity * @param ctx the bridge context to use */
protected static List extractStop(Element paintElement, float opacity, BridgeContext ctx) { List refs = new LinkedList(); for (;;) { List stops = extractLocalStop(paintElement, opacity, ctx); if (stops != null) { return stops; // stop elements found, exit } String uri = XLinkSupport.getXLinkHref(paintElement); if (uri.length() == 0) { return null; // no xlink:href found, exit } // check if there is circular dependencies String baseURI = paintElement.getBaseURI(); ParsedURL purl = new ParsedURL(baseURI, uri); if (contains(refs, purl)) { throw new BridgeException(ctx, paintElement, ERR_XLINK_HREF_CIRCULAR_DEPENDENCIES, new Object[] {uri}); } refs.add(purl); paintElement = ctx.getReferencedElement(paintElement, uri); } }
Returns a list of Stop elements, children of the specified paintElement can have or null if any.
Params:
  • gradientElement – the paint element
  • opacity – the opacity
  • ctx – the bridge context
/** * Returns a list of <code>Stop</code> elements, children of the * specified paintElement can have or null if any. * * @param gradientElement the paint element * @param opacity the opacity * @param ctx the bridge context */
protected static List extractLocalStop(Element gradientElement, float opacity, BridgeContext ctx) { LinkedList stops = null; Stop previous = null; for (Node n = gradientElement.getFirstChild(); n != null; n = n.getNextSibling()) { if ((n.getNodeType() != Node.ELEMENT_NODE)) { continue; } Element e = (Element)n; Bridge bridge = ctx.getBridge(e); if (bridge == null || !(bridge instanceof SVGStopElementBridge)) { continue; } Stop stop = ((SVGStopElementBridge)bridge).createStop (ctx, gradientElement, e, opacity); if (stops == null) { stops = new LinkedList(); } if (previous != null) { if (stop.offset < previous.offset) { stop.offset = previous.offset; } } stops.add(stop); previous = stop; } return stops; }
Returns true if the specified list of URLs contains the specified url.
Params:
  • urls – the list of URLs
  • key – the url to search for
/** * Returns true if the specified list of URLs contains the specified url. * * @param urls the list of URLs * @param key the url to search for */
private static boolean contains(List urls, ParsedURL key) { for (Object url : urls) { if (key.equals(url)) return true; } return false; }
This class represents a gradient <stop> element.
/** * This class represents a gradient &lt;stop&gt; element. */
public static class Stop {
The stop color.
/** The stop color. */
public Color color;
The stop offset.
/** The stop offset. */
public float offset;
Constructs a new stop definition.
Params:
  • color – the stop color
  • offset – the stop offset
/** * Constructs a new stop definition. * * @param color the stop color * @param offset the stop offset */
public Stop(Color color, float offset) { this.color = color; this.offset = offset; } }
Bridge class for the gradient <stop> element.
/** * Bridge class for the gradient &lt;stop&gt; element. */
public static class SVGStopElementBridge extends AnimatableGenericSVGBridge implements Bridge {
Returns 'stop'.
/** * Returns 'stop'. */
public String getLocalName() { return SVG_STOP_TAG; }
Creates a Stop according to the specified parameters.
Params:
  • ctx – the bridge context to use
  • gradientElement – the gradient element
  • stopElement – the stop element
  • opacity – an additional opacity of the stop color
/** * Creates a <code>Stop</code> according to the specified parameters. * * @param ctx the bridge context to use * @param gradientElement the gradient element * @param stopElement the stop element * @param opacity an additional opacity of the stop color */
public Stop createStop(BridgeContext ctx, Element gradientElement, Element stopElement, float opacity) { String s = stopElement.getAttributeNS(null, SVG_OFFSET_ATTRIBUTE); if (s.length() == 0) { throw new BridgeException (ctx, stopElement, ERR_ATTRIBUTE_MISSING, new Object[] {SVG_OFFSET_ATTRIBUTE}); } float offset; try { offset = SVGUtilities.convertRatio(s); } catch (NumberFormatException nfEx ) { throw new BridgeException (ctx, stopElement, nfEx, ERR_ATTRIBUTE_VALUE_MALFORMED, new Object[] {SVG_OFFSET_ATTRIBUTE, s, nfEx }); } Color color = CSSUtilities.convertStopColor(stopElement, opacity, ctx); return new Stop(color, offset); } } }