2362N/A * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. 0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 0N/A * This code is free software; you can redistribute it and/or modify it 0N/A * under the terms of the GNU General Public License version 2 only, as 2362N/A * published by the Free Software Foundation. Oracle designates this 0N/A * particular file as subject to the "Classpath" exception as provided 2362N/A * by Oracle in the LICENSE file that accompanied this code. 0N/A * This code is distributed in the hope that it will be useful, but WITHOUT 0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 0N/A * version 2 for more details (a copy is included in the LICENSE file that 0N/A * accompanied this code). 0N/A * You should have received a copy of the GNU General Public License version 0N/A * 2 along with this work; if not, write to the Free Software Foundation, 0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2362N/A * or visit www.oracle.com if you need additional information or have any 0N/A * Provides the actual implementation for the RadialGradientPaint. 0N/A * This is where the pixel processing is done. A RadialGradienPaint 0N/A * only supports circular gradients, but it should be possible to scale 0N/A * the circle to look approximately elliptical, by means of a 0N/A * gradient transform passed into the RadialGradientPaint constructor. 0N/A * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans 0N/A /** True when (focus == center). */ 0N/A /** True when (cycleMethod == NO_CYCLE). */ 0N/A /** Radius of the outermost circle defining the 100% gradient stop. */ 0N/A /** Variables representing center and focus points. */ 0N/A /** Radius of the gradient circle squared. */ 0N/A /** Constant part of X, Y user space coordinates. */ 0N/A /** Constant second order delta for simple loop. */ 0N/A * This value represents the solution when focusX == X. It is called 0N/A * trivial because it is easier to calculate than the general case. 0N/A /** Amount for offset when clamping focus. */ 0N/A * Constructor for RadialGradientPaintContext. 0N/A * @param paint the {@code RadialGradientPaint} from which this context 0N/A * @param cm the {@code ColorModel} that receives 0N/A * the {@code Paint} data (this is used only as a hint) 0N/A * @param deviceBounds the device space bounding box of the 0N/A * graphics primitive being rendered 0N/A * @param userBounds the user space bounding box of the 0N/A * graphics primitive being rendered 0N/A * @param t the {@code AffineTransform} from user 0N/A * space into device space (gradientTransform should be 0N/A * concatenated with this) 0N/A * @param hints the hints that the context object uses to choose 0N/A * between rendering alternatives 0N/A * @param cx the center X coordinate in user space of the circle defining 0N/A * the gradient. The last color of the gradient is mapped to 0N/A * the perimeter of this circle. 0N/A * @param cy the center Y coordinate in user space of the circle defining 0N/A * the gradient. The last color of the gradient is mapped to 0N/A * the perimeter of this circle. 0N/A * @param r the radius of the circle defining the extents of the 0N/A * @param fx the X coordinate in user space to which the first color 0N/A * @param fy the Y coordinate in user space to which the first color 0N/A * @param fractions the fractions specifying the gradient distribution 0N/A * @param colors the gradient colors 0N/A * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT 0N/A * @param colorSpace which colorspace to use for interpolation, 0N/A * either SRGB or LINEAR_RGB 0N/A // copy some parameters 0N/A // for use in the quadractic equation 0N/A // test if distance from focus to center is greater than the radius 0N/A // clamp focus to radius 0N/A // calculate the solution to be used in the case where X == focusX 0N/A // in cyclicCircularGradientFillRaster() 0N/A // constant parts of X, Y user space coordinates 0N/A // constant second order delta for simple loop 0N/A * Return a Raster containing the colors generated for the graphics 0N/A * @param x,y,w,h the area in device space for which colors are 0N/A int x,
int y,
int w,
int h)
0N/A * This code works in the simplest of cases, where the focus == center 0N/A * point, the gradient is noncyclic, and the gradient lookup method is 0N/A * fast (single array index, no conversion necessary). 0N/A int x,
int y,
int w,
int h)
0N/A /* We calculate sqrt(X^2 + Y^2) relative to the radius 0N/A * size to get the fraction for the color to use. 0N/A * Each step along the scanline adds (a00, a10) to (X, Y). 0N/A * If we precalculate: 0N/A * for the start of the row, then for each step we need to 0N/A * gRel' = (X+a00)^2 + (Y+a10)^2 0N/A * = X^2 + 2*X*a00 + a00^2 + Y^2 + 2*Y*a10 + a10^2 0N/A * = (X^2+Y^2) + 2*(X*a00+Y*a10) + (a00^2+a10^2) 0N/A * = gRel + 2*(X*a00+Y*a10) + (a00^2+a10^2) 0N/A * = gRel + 2*DP + SD 0N/A * (where DP = dot product between X,Y and a00,a10 0N/A * and SD = dot product square of the delta vector) 0N/A * For the step after that we get: 0N/A * gRel'' = (X+2*a00)^2 + (Y+2*a10)^2 0N/A * = X^2 + 4*X*a00 + 4*a00^2 + Y^2 + 4*Y*a10 + 4*a10^2 0N/A * = (X^2+Y^2) + 4*(X*a00+Y*a10) + 4*(a00^2+a10^2) 0N/A * = gRel + 4*DP + 4*SD 0N/A * = gRel' + 2*DP + 3*SD 0N/A * The increment changed by: 0N/A * (gRel'' - gRel') - (gRel' - gRel) 0N/A * = (2*DP + 3*SD) - (2*DP + SD) 0N/A * Note that this value depends only on the (inverse of the) 0N/A * transformation matrix and so is a constant for the loop. 0N/A * To make this all relative to the unit circle, we need to 0N/A * divide all values as follows: 0N/A // coordinates of UL corner in "user space" relative to center 0N/A // second order delta calculated in constructor 0N/A // adjust is (scan-w) of pixels array, we need (scan) 0N/A // rgb of the 1.0 color used when the distance exceeds gradient radius 0N/A for (
int j =
0; j < h; j++) {
0N/A // these values depend on the coordinates of the start of the row 0N/A /* Use optimized loops for any cases where gRel >= 1. 0N/A * We do not need to calculate sqrt(gRel) for these 0N/A * values since sqrt(N>=1) == (M>=1). 0N/A * Note that gRel follows a parabola which can only be < 1 0N/A * for a small region around the center on each scanline. In 0N/A * gDeltaDelta is always positive 0N/A * gDelta is <0 until it crosses the midpoint, then >0 0N/A * To the left and right of that region, it will always be 0N/A * >=1 out to infinity, so we can process the line in 3 0N/A * out to the left - quick fill until gRel < 1, updating gRel 0N/A * in the heart - slow fraction=sqrt fill while gRel < 1 0N/A * out to the right - quick fill rest of scanline, ignore gRel 0N/A // Quick fill for "out to the left" 0N/A // Slow fill for "in the heart" 0N/A // store the color at this point 0N/A // incremental calculation 0N/A // Quick fill to end of line for "out to the right" 0N/A // SQRT_LUT_SIZE must be a power of 2 for the test above to work. 0N/A * Fill the raster, cycling the gradient colors when a point falls outside 0N/A * of the perimeter of the 100% stop circle. 0N/A * This calculation first computes the intersection point of the line 0N/A * from the focus through the current point in the raster, and the 0N/A * perimeter of the gradient circle. 0N/A * Then it determines the percentage distance of the current point along 0N/A * that line (focus is 0%, perimeter is 100%). 0N/A * Equation of a circle centered at (a,b) with radius r: 0N/A * (x-a)^2 + (y-b)^2 = r^2 0N/A * Equation of a line with slope m and y-intercept b: 0N/A * Replacing y in the circle equation and solving using the quadratic 0N/A * formula produces the following set of equations. Constant factors have 0N/A * been extracted out of the inner loop. 0N/A // constant part of the C factor of the quadratic equation 0N/A // coefficients of the quadratic equation (Ax^2 + Bx + C = 0) 0N/A // slope and y-intercept of the focus-perimeter line 0N/A // intersection with circle X,Y coordinate 0N/A // constant parts of X, Y coordinates 0N/A // constants in inner loop quadratic formula 0N/A // value between 0 and 1 specifying position in the gradient 0N/A // determinant of quadratic formula (should always be > 0) 0N/A // sq distance from the current point to focus 0N/A // sq distance from the intersect point to focus 0N/A // temp variables for change in X,Y squared 0N/A // used to index pixels array 0N/A // incremental index change for pixels array 0N/A for (
int j =
0; j < h; j++) {
0N/A // user space point; these are constant from column to column 0N/A // for every column (inner loop begins here) 0N/A for (
int i =
0; i < w; i++) {
0N/A // special case to avoid divide by zero 0N/A // slope and y-intercept of the focus-perimeter line 0N/A // use the quadratic formula to calculate the 0N/A // intersection point 0N/A // choose the positive or negative root depending 0N/A // on where the X coord lies with respect to the focus 0N/A // Calculate the square of the distance from the current point 0N/A // to the focus and the square of the distance from the 0N/A // intersection point to the focus. Want the squares so we can 0N/A // do 1 square root after division instead of 2 before. 0N/A // get the percentage (0-1) of the current point along the 0N/A // focus-circumference line 0N/A // store the color at this point 0N/A // incremental change in X, Y