1/* 2 * Copyright (c) 2006, 2013, 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 26package java.awt; 27 28import java.awt.MultipleGradientPaint.CycleMethod; 29import java.awt.MultipleGradientPaint.ColorSpaceType; 30import java.awt.geom.AffineTransform; 31import java.awt.geom.Point2D; 32import java.awt.geom.Rectangle2D; 33import java.awt.image.ColorModel; 34 35/** 36 * Provides the actual implementation for the LinearGradientPaint. 37 * This is where the pixel processing is done. 38 * 39 * @see java.awt.LinearGradientPaint 40 * @see java.awt.PaintContext 41 * @see java.awt.Paint 42 * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans 43 */ 44final class LinearGradientPaintContext extends MultipleGradientPaintContext { 45 46 /** 47 * The following invariants are used to process the gradient value from 48 * a device space coordinate, (X, Y): 49 * g(X, Y) = dgdX*X + dgdY*Y + gc 50 */ 51 private float dgdX, dgdY, gc; 52 53 /** 54 * Constructor for LinearGradientPaintContext. 55 * 56 * @param paint the {@code LinearGradientPaint} from which this context 57 * is created 58 * @param cm {@code ColorModel} that receives 59 * the {@code Paint} data. This is used only as a hint. 60 * @param deviceBounds the device space bounding box of the 61 * graphics primitive being rendered 62 * @param userBounds the user space bounding box of the 63 * graphics primitive being rendered 64 * @param t the {@code AffineTransform} from user 65 * space into device space (gradientTransform should be 66 * concatenated with this) 67 * @param hints the hints that the context object uses to choose 68 * between rendering alternatives 69 * @param start gradient start point, in user space 70 * @param end gradient end point, in user space 71 * @param fractions the fractions specifying the gradient distribution 72 * @param colors the gradient colors 73 * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT 74 * @param colorSpace which colorspace to use for interpolation, 75 * either SRGB or LINEAR_RGB 76 */ 77 LinearGradientPaintContext(LinearGradientPaint paint, 78 ColorModel cm, 79 Rectangle deviceBounds, 80 Rectangle2D userBounds, 81 AffineTransform t, 82 RenderingHints hints, 83 Point2D start, 84 Point2D end, 85 float[] fractions, 86 Color[] colors, 87 CycleMethod cycleMethod, 88 ColorSpaceType colorSpace) 89 { 90 super(paint, cm, deviceBounds, userBounds, t, hints, fractions, 91 colors, cycleMethod, colorSpace); 92 93 // A given point in the raster should take on the same color as its 94 // projection onto the gradient vector. 95 // Thus, we want the projection of the current position vector 96 // onto the gradient vector, then normalized with respect to the 97 // length of the gradient vector, giving a value which can be mapped 98 // into the range 0-1. 99 // projection = 100 // currentVector dot gradientVector / length(gradientVector) 101 // normalized = projection / length(gradientVector) 102 103 float startx = (float)start.getX(); 104 float starty = (float)start.getY(); 105 float endx = (float)end.getX(); 106 float endy = (float)end.getY(); 107 108 float dx = endx - startx; // change in x from start to end 109 float dy = endy - starty; // change in y from start to end 110 float dSq = dx*dx + dy*dy; // total distance squared 111 112 // avoid repeated calculations by doing these divides once 113 float constX = dx/dSq; 114 float constY = dy/dSq; 115 116 // incremental change along gradient for +x 117 dgdX = a00*constX + a10*constY; 118 // incremental change along gradient for +y 119 dgdY = a01*constX + a11*constY; 120 121 // constant, incorporates the translation components from the matrix 122 gc = (a02-startx)*constX + (a12-starty)*constY; 123 } 124 125 /** 126 * Return a Raster containing the colors generated for the graphics 127 * operation. This is where the area is filled with colors distributed 128 * linearly. 129 * 130 * @param x,y,w,h the area in device space for which colors are 131 * generated. 132 */ 133 protected void fillRaster(int[] pixels, int off, int adjust, 134 int x, int y, int w, int h) 135 { 136 // current value for row gradients 137 float g = 0; 138 139 // used to end iteration on rows 140 int rowLimit = off + w; 141 142 // constant which can be pulled out of the inner loop 143 float initConst = (dgdX*x) + gc; 144 145 for (int i = 0; i < h; i++) { // for every row 146 147 // initialize current value to be start 148 g = initConst + dgdY*(y+i); 149 150 while (off < rowLimit) { // for every pixel in this row 151 // get the color 152 pixels[off++] = indexIntoGradientsArrays(g); 153 154 // incremental change in g 155 g += dgdX; 156 } 157 158 // change in off from row to row 159 off += adjust; 160 161 //rowlimit is width + offset 162 rowLimit = off + w; 163 } 164 } 165} 166