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.MultipleGradientPaint.CycleMethod;
029 import java.awt.MultipleGradientPaint.ColorSpaceType;
030 import java.awt.geom.AffineTransform;
031 import java.awt.geom.Point2D;
032 import java.awt.geom.Rectangle2D;
033 import java.awt.image.ColorModel;
034
035 /**
036 * Provides the actual implementation for the LinearGradientPaint.
037 * This is where the pixel processing is done.
038 *
039 * @see java.awt.LinearGradientPaint
040 * @see java.awt.PaintContext
041 * @see java.awt.Paint
042 * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans
043 */
044 final class LinearGradientPaintContext extends
045 MultipleGradientPaintContext {
046
047 /**
048 * The following invariants are used to process the gradient value from
049 * a device space coordinate, (X, Y):
050 * g(X, Y) = dgdX*X + dgdY*Y + gc
051 */
052 private float dgdX, dgdY, gc;
053
054 /**
055 * Constructor for LinearGradientPaintContext.
056 *
057 * @param paint the {@code LinearGradientPaint} from which this context
058 * is created
059 * @param cm {@code ColorModel} that receives
060 * the <code>Paint</code> data. This is used only as a hint.
061 * @param deviceBounds the device space bounding box of the
062 * graphics primitive being rendered
063 * @param userBounds the user space bounding box of the
064 * graphics primitive being rendered
065 * @param t the {@code AffineTransform} from user
066 * space into device space (gradientTransform should be
067 * concatenated with this)
068 * @param hints the hints that the context object uses to choose
069 * between rendering alternatives
070 * @param dStart gradient start point, in user space
071 * @param dEnd gradient end point, in user space
072 * @param fractions the fractions specifying the gradient distribution
073 * @param colors the gradient colors
074 * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT
075 * @param colorSpace which colorspace to use for interpolation,
076 * either SRGB or LINEAR_RGB
077 */
078 LinearGradientPaintContext(LinearGradientPaint paint,
079 ColorModel cm, Rectangle deviceBounds,
080 Rectangle2D userBounds, AffineTransform t,
081 RenderingHints hints, Point2D start, Point2D end,
082 float[] fractions, Color[] colors, CycleMethod cycleMethod,
083 ColorSpaceType colorSpace) {
084 super (paint, cm, deviceBounds, userBounds, t, hints, fractions,
085 colors, cycleMethod, colorSpace);
086
087 // A given point in the raster should take on the same color as its
088 // projection onto the gradient vector.
089 // Thus, we want the projection of the current position vector
090 // onto the gradient vector, then normalized with respect to the
091 // length of the gradient vector, giving a value which can be mapped
092 // into the range 0-1.
093 // projection =
094 // currentVector dot gradientVector / length(gradientVector)
095 // normalized = projection / length(gradientVector)
096
097 float startx = (float) start.getX();
098 float starty = (float) start.getY();
099 float endx = (float) end.getX();
100 float endy = (float) end.getY();
101
102 float dx = endx - startx; // change in x from start to end
103 float dy = endy - starty; // change in y from start to end
104 float dSq = dx * dx + dy * dy; // total distance squared
105
106 // avoid repeated calculations by doing these divides once
107 float constX = dx / dSq;
108 float constY = dy / dSq;
109
110 // incremental change along gradient for +x
111 dgdX = a00 * constX + a10 * constY;
112 // incremental change along gradient for +y
113 dgdY = a01 * constX + a11 * constY;
114
115 // constant, incorporates the translation components from the matrix
116 gc = (a02 - startx) * constX + (a12 - starty) * constY;
117 }
118
119 /**
120 * Return a Raster containing the colors generated for the graphics
121 * operation. This is where the area is filled with colors distributed
122 * linearly.
123 *
124 * @param x,y,w,h the area in device space for which colors are
125 * generated.
126 */
127 protected void fillRaster(int[] pixels, int off, int adjust, int x,
128 int y, int w, int h) {
129 // current value for row gradients
130 float g = 0;
131
132 // used to end iteration on rows
133 int rowLimit = off + w;
134
135 // constant which can be pulled out of the inner loop
136 float initConst = (dgdX * x) + gc;
137
138 for (int i = 0; i < h; i++) { // for every row
139
140 // initialize current value to be start
141 g = initConst + dgdY * (y + i);
142
143 while (off < rowLimit) { // for every pixel in this row
144 // get the color
145 pixels[off++] = indexIntoGradientsArrays(g);
146
147 // incremental change in g
148 g += dgdX;
149 }
150
151 // change in off from row to row
152 off += adjust;
153
154 //rowlimit is width + offset
155 rowLimit = off + w;
156 }
157 }
158 }
|