1 /* 2 * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.awt; 27 28 import java.awt.geom.AffineTransform; 29 import java.awt.image.ColorModel; 30 import java.lang.ref.SoftReference; 31 import java.util.Arrays; 32 33 /** 34 * This is the superclass for Paints which use a multiple color 35 * gradient to fill in their raster. It provides storage for variables and 36 * enumerated values common to 37 * {@code LinearGradientPaint} and {@code RadialGradientPaint}. 38 * 39 * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans 40 * @since 1.6 41 */ 42 public abstract class MultipleGradientPaint implements Paint { 43 44 /** The method to use when painting outside the gradient bounds. 45 * @since 1.6 46 */ 47 public static enum CycleMethod { 48 /** 49 * Use the terminal colors to fill the remaining area. 50 */ 51 NO_CYCLE, 52 53 /** 54 * Cycle the gradient colors start-to-end, end-to-start 55 * to fill the remaining area. 56 */ 57 REFLECT, 58 59 /** 60 * Cycle the gradient colors start-to-end, start-to-end 61 * to fill the remaining area. 62 */ 63 REPEAT 64 } 65 66 /** The color space in which to perform the gradient interpolation. 67 * @since 1.6 68 */ 69 public static enum ColorSpaceType { 70 /** 71 * Indicates that the color interpolation should occur in sRGB space. 72 */ 73 SRGB, 74 75 /** 76 * Indicates that the color interpolation should occur in linearized 77 * RGB space. 78 */ 79 LINEAR_RGB 80 } 81 82 /** The transparency of this paint object. */ 83 final int transparency; 84 85 /** Gradient keyframe values in the range 0 to 1. */ 86 final float[] fractions; 87 88 /** Gradient colors. */ 89 final Color[] colors; 90 91 /** Transform to apply to gradient. */ 92 final AffineTransform gradientTransform; 93 94 /** The method to use when painting outside the gradient bounds. */ 95 final CycleMethod cycleMethod; 96 97 /** The color space in which to perform the gradient interpolation. */ 98 final ColorSpaceType colorSpace; 99 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 */ MultipleGradientPaint(float[] fractions, Color[] colors, CycleMethod cycleMethod, ColorSpaceType colorSpace, AffineTransform gradientTransform)136 MultipleGradientPaint(float[] fractions, 137 Color[] colors, 138 CycleMethod cycleMethod, 139 ColorSpaceType colorSpace, 140 AffineTransform gradientTransform) 141 { 142 if (fractions == null) { 143 throw new NullPointerException("Fractions array cannot be null"); 144 } 145 146 if (colors == null) { 147 throw new NullPointerException("Colors array cannot be null"); 148 } 149 150 if (cycleMethod == null) { 151 throw new NullPointerException("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("Gradient transform cannot be "+ 160 "null"); 161 } 162 163 if (fractions.length != colors.length) { 164 throw new IllegalArgumentException("Colors and fractions must " + 165 "have equal size"); 166 } 167 168 if (colors.length < 2) { 169 throw new IllegalArgumentException("User must specify at least " + 170 "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("Fraction values must " + 179 "be in the range 0 to 1: " + 180 currentFraction); 181 } 182 183 if (currentFraction <= previousFraction) { 184 throw new IllegalArgumentException("Keyframe fractions " + 185 "must be increasing: " + 186 currentFraction); 187 } 188 189 previousFraction = currentFraction; 190 } 191 192 // We have to deal with the cases where the first gradient stop is not 193 // equal to 0 and/or the last gradient stop is not equal to 1. 194 // In both cases, create a new point and replicate the previous 195 // extreme point's color. 196 boolean fixFirst = false; 197 boolean fixLast = false; 198 int len = fractions.length; 199 int off = 0; 200 201 if (fractions[0] != 0f) { 202 // first stop is not equal to zero, fix this condition 203 fixFirst = true; 204 len++; 205 off++; 206 } 207 if (fractions[fractions.length-1] != 1f) { 208 // last stop is not equal to one, fix this condition 209 fixLast = true; 210 len++; 211 } 212 213 this.fractions = new float[len]; 214 System.arraycopy(fractions, 0, this.fractions, off, fractions.length); 215 this.colors = new Color[len]; 216 System.arraycopy(colors, 0, this.colors, off, colors.length); 217 218 if (fixFirst) { 219 this.fractions[0] = 0f; 220 this.colors[0] = colors[0]; 221 } 222 if (fixLast) { 223 this.fractions[len-1] = 1f; 224 this.colors[len-1] = colors[colors.length - 1]; 225 } 226 227 // copy some flags 228 this.colorSpace = colorSpace; 229 this.cycleMethod = cycleMethod; 230 231 // copy the gradient transform 232 this.gradientTransform = new AffineTransform(gradientTransform); 233 234 // determine transparency 235 boolean opaque = true; 236 for (int i = 0; i < colors.length; i++){ 237 opaque = opaque && (colors[i].getAlpha() == 0xff); 238 } 239 this.transparency = opaque ? OPAQUE : TRANSLUCENT; 240 } 241 242 /** 243 * Returns a copy of the array of floats used by this gradient 244 * to calculate color distribution. 245 * The returned array always has 0 as its first value and 1 as its 246 * last value, with increasing values in between. 247 * 248 * @return a copy of the array of floats used by this gradient to 249 * calculate color distribution 250 */ getFractions()251 public final float[] getFractions() { 252 return Arrays.copyOf(fractions, fractions.length); 253 } 254 255 /** 256 * Returns a copy of the array of colors used by this gradient. 257 * The first color maps to the first value in the fractions array, 258 * and the last color maps to the last value in the fractions array. 259 * 260 * @return a copy of the array of colors used by this gradient 261 */ getColors()262 public final Color[] getColors() { 263 return Arrays.copyOf(colors, colors.length); 264 } 265 266 /** 267 * Returns the enumerated type which specifies cycling behavior. 268 * 269 * @return the enumerated type which specifies cycling behavior 270 */ getCycleMethod()271 public final CycleMethod getCycleMethod() { 272 return cycleMethod; 273 } 274 275 /** 276 * Returns the enumerated type which specifies color space for 277 * interpolation. 278 * 279 * @return the enumerated type which specifies color space for 280 * interpolation 281 */ getColorSpace()282 public final ColorSpaceType getColorSpace() { 283 return colorSpace; 284 } 285 286 /** 287 * Returns a copy of the transform applied to the gradient. 288 * 289 * <p> 290 * Note that if no transform is applied to the gradient 291 * when it is created, the identity transform is used. 292 * 293 * @return a copy of the transform applied to the gradient 294 */ getTransform()295 public final AffineTransform getTransform() { 296 return new AffineTransform(gradientTransform); 297 } 298 299 /** 300 * Returns the transparency mode for this {@code Paint} object. 301 * 302 * @return {@code OPAQUE} if all colors used by this 303 * {@code Paint} object are opaque, 304 * {@code TRANSLUCENT} if at least one of the 305 * colors used by this {@code Paint} object is not opaque. 306 * @see java.awt.Transparency 307 */ getTransparency()308 public final int getTransparency() { 309 return transparency; 310 } 311 } 312