001/*****************************************************************************
002 * Copyright (C) The Apache Software Foundation. All rights reserved.        *
003 * ------------------------------------------------------------------------- *
004 * This software is published under the terms of the Apache Software License *
005 * version 1.1, a copy of which has been included with this distribution in  *
006 * the LICENSE file.                                                         *
007 *****************************************************************************/
008
009package com.kitfox.svg.batik;
010
011import java.awt.Color;
012import java.awt.Paint;
013import java.awt.geom.AffineTransform;
014
015/** This is the superclass for Paints which use a multiple color
016 * gradient to fill in their raster.  It provides storage for variables and
017 * enumerated values common to LinearGradientPaint and RadialGradientPaint.
018 *
019 *
020 * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans
021 * @author <a href="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
022 * @version $Id: MultipleGradientPaint.java,v 1.2 2004/09/27 09:27:27 kitfox Exp $
023 *
024 */
025
026public abstract class MultipleGradientPaint implements Paint {
027
028    /** Transparency. */
029    protected int transparency;
030
031    /** Gradient keyframe values in the range 0 to 1. */
032    protected float[] fractions;
033
034    /** Gradient colors. */
035    protected Color[] colors;
036
037    /** Transform to apply to gradient. */
038    protected AffineTransform gradientTransform;
039
040    /** The method to use when painting out of the gradient bounds. */
041    protected CycleMethodEnum cycleMethod;
042
043    /** The colorSpace in which to perform the interpolation. */
044    protected ColorSpaceEnum colorSpace;
045
046    /** Inner class to allow for typesafe enumerated ColorSpace values. */
047    public static class ColorSpaceEnum {
048    }
049
050    /** Inner class to allow for typesafe enumerated CycleMethod values. */
051    public static class CycleMethodEnum {
052    }
053
054    /** Indicates (if the gradient starts or ends inside the target region)
055     *  to use the terminal colors to fill the remaining area. (default)
056     */
057    public static final CycleMethodEnum NO_CYCLE = new CycleMethodEnum();
058
059    /** Indicates (if the gradient starts or ends inside the target region),
060     *  to cycle the gradient colors start-to-end, end-to-start to fill the
061     *  remaining area.
062     */
063    public static final CycleMethodEnum REFLECT = new CycleMethodEnum();
064
065    /** Indicates (if the gradient starts or ends inside the target region),
066     *  to cycle the gradient colors start-to-end, start-to-end to fill the
067     *  remaining area.
068     */
069    public static final CycleMethodEnum REPEAT = new CycleMethodEnum();
070
071    /** Indicates that the color interpolation should occur in sRGB space.
072     *  (default)
073     */
074    public static final ColorSpaceEnum SRGB = new ColorSpaceEnum();
075
076    /** Indicates that the color interpolation should occur in linearized
077     *  RGB space.
078     */
079    public static final ColorSpaceEnum LINEAR_RGB = new ColorSpaceEnum();
080
081
082     /**
083     * Superclass constructor, typical user should never have to call this.
084     *
085     * @param fractions numbers ranging from 0.0 to 1.0 specifying the
086     * distribution of colors along the gradient
087     *
088     * @param colors array of colors corresponding to each fractional value
089     *
090     * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT
091     *
092     * @param colorSpace which colorspace to use for interpolation,
093     * either SRGB or LINEAR_RGB
094     *
095     * @param gradientTransform transform to apply to the gradient
096     *
097     * @throws NullPointerException if arrays are null, or
098     * gradientTransform is null
099     *
100     * @throws IllegalArgumentException if fractions.length != colors.length,
101     * or if colors is less than 2 in size, or if an enumerated value is bad.
102     *
103     * @see java.awt.PaintContext
104     */
105    public MultipleGradientPaint(float[] fractions,
106                                 Color[] colors,
107                                 CycleMethodEnum cycleMethod,
108                                 ColorSpaceEnum colorSpace,
109                                 AffineTransform gradientTransform) {
110
111        if (fractions == null) {
112            throw new IllegalArgumentException("Fractions array cannot be " +
113                                               "null");
114        }
115
116        if (colors == null) {
117            throw new IllegalArgumentException("Colors array cannot be null");
118        }
119
120        if (fractions.length != colors.length) {
121            throw new IllegalArgumentException("Colors and fractions must " +
122                                               "have equal size");
123        }
124
125        if (colors.length < 2) {
126            throw new IllegalArgumentException("User must specify at least " +
127                                               "2 colors");
128        }
129
130        if ((colorSpace != LINEAR_RGB) &&
131            (colorSpace != SRGB)) {
132            throw new IllegalArgumentException("Invalid colorspace for " +
133                                               "interpolation.");
134        }
135
136        if ((cycleMethod != NO_CYCLE) &&
137            (cycleMethod != REFLECT) &&
138            (cycleMethod != REPEAT)) {
139            throw new IllegalArgumentException("Invalid cycle method.");
140        }
141
142        if (gradientTransform == null) {
143            throw new IllegalArgumentException("Gradient transform cannot be "+
144                                               "null.");
145        }
146
147        //copy the fractions array
148        this.fractions = new float[fractions.length];
149        System.arraycopy(fractions, 0, this.fractions, 0, fractions.length);
150
151        //copy the colors array
152        this.colors = new Color[colors.length];
153        System.arraycopy(colors, 0, this.colors, 0, colors.length);
154
155        //copy some flags
156        this.colorSpace = colorSpace;
157        this.cycleMethod = cycleMethod;
158
159        //copy the gradient transform
160        this.gradientTransform = (AffineTransform)gradientTransform.clone();
161
162        // Process transparency
163        boolean opaque = true;
164        for(int i=0; i<colors.length; i++){
165            opaque = opaque && (colors[i].getAlpha()==0xff);
166        }
167
168        if(opaque) {
169            transparency = OPAQUE;
170        }
171
172        else {
173            transparency = TRANSLUCENT;
174        }
175    }
176
177    /**
178     * Returns a copy of the array of colors used by this gradient.
179     * @return a copy of the array of colors used by this gradient
180     *
181     */
182    public Color[] getColors() {
183        Color colors[] = new Color[this.colors.length];
184        System.arraycopy(this.colors, 0, colors, 0, this.colors.length);
185        return colors;
186    }
187
188    /**
189     * Returns a copy of the array of floats used by this gradient
190     * to calculate color distribution.
191     * @return a copy of the array of floats used by this gradient to
192     * calculate color distribution
193     *
194     */
195    public float[] getFractions() {
196        float fractions[] = new float[this.fractions.length];
197        System.arraycopy(this.fractions, 0, fractions, 0, this.fractions.length);
198        return fractions;
199    }
200
201    /**
202     * Returns the transparency mode for this LinearGradientPaint.
203     * @return an integer value representing this LinearGradientPaint object's
204     * transparency mode.
205     * @see java.awt.Transparency
206     */
207    public int getTransparency() {
208        return transparency;
209    }
210
211    /**
212     * Returns the enumerated type which specifies cycling behavior.
213     * @return the enumerated type which specifies cycling behavior
214     */
215    public CycleMethodEnum getCycleMethod() {
216        return cycleMethod;
217    }
218
219    /**
220     * Returns the enumerated type which specifies color space for
221     * interpolation.
222     * @return the enumerated type which specifies color space for
223     * interpolation
224     */
225    public ColorSpaceEnum getColorSpace() {
226        return colorSpace;
227    }
228
229    /**
230     * Returns a copy of the transform applied to the gradient.
231     * @return a copy of the transform applied to the gradient.
232     */
233    public AffineTransform getTransform() {
234        return (AffineTransform)gradientTransform.clone();
235    }
236}