001 /*
002 * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation. Sun designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Sun in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022 * CA 95054 USA or visit www.sun.com if you need additional information or
023 * have any questions.
024 */
025
026 package java.awt;
027
028 import java.awt.geom.AffineTransform;
029 import java.awt.image.ColorModel;
030 import java.lang.ref.SoftReference;
031 import java.util.Arrays;
032
033 /**
034 * This is the superclass for Paints which use a multiple color
035 * gradient to fill in their raster. It provides storage for variables and
036 * enumerated values common to
037 * {@code LinearGradientPaint} and {@code RadialGradientPaint}.
038 *
039 * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans
040 * @since 1.6
041 */
042 public abstract class MultipleGradientPaint implements Paint {
043
044 /** The method to use when painting outside the gradient bounds.
045 * @since 1.6
046 */
047 public static enum CycleMethod {
048 /**
049 * Use the terminal colors to fill the remaining area.
050 */
051 NO_CYCLE,
052
053 /**
054 * Cycle the gradient colors start-to-end, end-to-start
055 * to fill the remaining area.
056 */
057 REFLECT,
058
059 /**
060 * Cycle the gradient colors start-to-end, start-to-end
061 * to fill the remaining area.
062 */
063 REPEAT
064 }
065
066 /** The color space in which to perform the gradient interpolation.
067 * @since 1.6
068 */
069 public static enum ColorSpaceType {
070 /**
071 * Indicates that the color interpolation should occur in sRGB space.
072 */
073 SRGB,
074
075 /**
076 * Indicates that the color interpolation should occur in linearized
077 * RGB space.
078 */
079 LINEAR_RGB
080 }
081
082 /** The transparency of this paint object. */
083 final int transparency;
084
085 /** Gradient keyframe values in the range 0 to 1. */
086 final float[] fractions;
087
088 /** Gradient colors. */
089 final Color[] colors;
090
091 /** Transform to apply to gradient. */
092 final AffineTransform gradientTransform;
093
094 /** The method to use when painting outside the gradient bounds. */
095 final CycleMethod cycleMethod;
096
097 /** The color space in which to perform the gradient interpolation. */
098 final ColorSpaceType colorSpace;
099
100 /**
101 * The following fields are used only by MultipleGradientPaintContext
102 * to cache certain values that remain constant and do not need to be
103 * recalculated for each context created from this paint instance.
104 */
105 ColorModel model;
106 float[] normalizedIntervals;
107 boolean isSimpleLookup;
108 SoftReference<int[][]> gradients;
109 SoftReference<int[]> gradient;
110 int fastGradientArraySize;
111
112 /**
113 * Package-private constructor.
114 *
115 * @param fractions numbers ranging from 0.0 to 1.0 specifying the
116 * distribution of colors along the gradient
117 * @param colors array of colors corresponding to each fractional value
118 * @param cycleMethod either {@code NO_CYCLE}, {@code REFLECT},
119 * or {@code REPEAT}
120 * @param colorSpace which color space to use for interpolation,
121 * either {@code SRGB} or {@code LINEAR_RGB}
122 * @param gradientTransform transform to apply to the gradient
123 *
124 * @throws NullPointerException
125 * if {@code fractions} array is null,
126 * or {@code colors} array is null,
127 * or {@code gradientTransform} is null,
128 * or {@code cycleMethod} is null,
129 * or {@code colorSpace} is null
130 * @throws IllegalArgumentException
131 * if {@code fractions.length != colors.length},
132 * or {@code colors} is less than 2 in size,
133 * or a {@code fractions} value is less than 0.0 or greater than 1.0,
134 * or the {@code fractions} are not provided in strictly increasing order
135 */
136 MultipleGradientPaint(float[] fractions, Color[] colors,
137 CycleMethod cycleMethod, ColorSpaceType colorSpace,
138 AffineTransform gradientTransform) {
139 if (fractions == null) {
140 throw new NullPointerException(
141 "Fractions array cannot be null");
142 }
143
144 if (colors == null) {
145 throw new NullPointerException(
146 "Colors array cannot be null");
147 }
148
149 if (cycleMethod == null) {
150 throw new NullPointerException(
151 "Cycle method cannot be null");
152 }
153
154 if (colorSpace == null) {
155 throw new NullPointerException("Color space cannot be null");
156 }
157
158 if (gradientTransform == null) {
159 throw new NullPointerException(
160 "Gradient transform cannot be " + "null");
161 }
162
163 if (fractions.length != colors.length) {
164 throw new IllegalArgumentException(
165 "Colors and fractions must " + "have equal size");
166 }
167
168 if (colors.length < 2) {
169 throw new IllegalArgumentException(
170 "User must specify at least " + "2 colors");
171 }
172
173 // check that values are in the proper range and progress
174 // in increasing order from 0 to 1
175 float previousFraction = -1.0f;
176 for (float currentFraction : fractions) {
177 if (currentFraction < 0f || currentFraction > 1f) {
178 throw new IllegalArgumentException(
179 "Fraction values must "
180 + "be in the range 0 to 1: "
181 + currentFraction);
182 }
183
184 if (currentFraction <= previousFraction) {
185 throw new IllegalArgumentException(
186 "Keyframe fractions " + "must be increasing: "
187 + currentFraction);
188 }
189
190 previousFraction = currentFraction;
191 }
192
193 // We have to deal with the cases where the first gradient stop is not
194 // equal to 0 and/or the last gradient stop is not equal to 1.
195 // In both cases, create a new point and replicate the previous
196 // extreme point's color.
197 boolean fixFirst = false;
198 boolean fixLast = false;
199 int len = fractions.length;
200 int off = 0;
201
202 if (fractions[0] != 0f) {
203 // first stop is not equal to zero, fix this condition
204 fixFirst = true;
205 len++;
206 off++;
207 }
208 if (fractions[fractions.length - 1] != 1f) {
209 // last stop is not equal to one, fix this condition
210 fixLast = true;
211 len++;
212 }
213
214 this .fractions = new float[len];
215 System.arraycopy(fractions, 0, this .fractions, off,
216 fractions.length);
217 this .colors = new Color[len];
218 System.arraycopy(colors, 0, this .colors, off, colors.length);
219
220 if (fixFirst) {
221 this .fractions[0] = 0f;
222 this .colors[0] = colors[0];
223 }
224 if (fixLast) {
225 this .fractions[len - 1] = 1f;
226 this .colors[len - 1] = colors[colors.length - 1];
227 }
228
229 // copy some flags
230 this .colorSpace = colorSpace;
231 this .cycleMethod = cycleMethod;
232
233 // copy the gradient transform
234 this .gradientTransform = new AffineTransform(gradientTransform);
235
236 // determine transparency
237 boolean opaque = true;
238 for (int i = 0; i < colors.length; i++) {
239 opaque = opaque && (colors[i].getAlpha() == 0xff);
240 }
241 this .transparency = opaque ? OPAQUE : TRANSLUCENT;
242 }
243
244 /**
245 * Returns a copy of the array of floats used by this gradient
246 * to calculate color distribution.
247 * The returned array always has 0 as its first value and 1 as its
248 * last value, with increasing values in between.
249 *
250 * @return a copy of the array of floats used by this gradient to
251 * calculate color distribution
252 */
253 public final float[] getFractions() {
254 return Arrays.copyOf(fractions, fractions.length);
255 }
256
257 /**
258 * Returns a copy of the array of colors used by this gradient.
259 * The first color maps to the first value in the fractions array,
260 * and the last color maps to the last value in the fractions array.
261 *
262 * @return a copy of the array of colors used by this gradient
263 */
264 public final Color[] getColors() {
265 return Arrays.copyOf(colors, colors.length);
266 }
267
268 /**
269 * Returns the enumerated type which specifies cycling behavior.
270 *
271 * @return the enumerated type which specifies cycling behavior
272 */
273 public final CycleMethod getCycleMethod() {
274 return cycleMethod;
275 }
276
277 /**
278 * Returns the enumerated type which specifies color space for
279 * interpolation.
280 *
281 * @return the enumerated type which specifies color space for
282 * interpolation
283 */
284 public final ColorSpaceType getColorSpace() {
285 return colorSpace;
286 }
287
288 /**
289 * Returns a copy of the transform applied to the gradient.
290 *
291 * @return a copy of the transform applied to the gradient
292 */
293 public final AffineTransform getTransform() {
294 return new AffineTransform(gradientTransform);
295 }
296
297 /**
298 * Returns the transparency mode for this Paint object.
299 *
300 * @return an integer value representing the transparency mode for
301 * this Paint object
302 * @see java.awt.Transparency
303 */
304 public final int getTransparency() {
305 return transparency;
306 }
307 }
|