deweese 01/07/11 05:24:02 Modified: sources/org/apache/batik/bridge AbstractSVGGradientElementBridge.java sources/org/apache/batik/ext/awt MultipleGradientPaintContext.java RadialGradientPaintContext.java sources/org/apache/batik/util ParsedURL.java ParsedURLData.java Added: samples/tests radialGradient2.svg Log: 1) Removed use of java.net.URL.getPath (JDK 1.3ism). 2) Fixed handling of stops that use the same offset value. 3) Added test file for #1 (also test complex lookup gradient code). 4) Added anti-aliased implementation of gradient lookup code. The use of anti-aliasing is currently controlled by the private final static USE_ANTI_ALIAS in RadialGradientPaintContext. Compare radialGradient2 with and without anti-aliasing :) PR: 1563 Revision Changes Path 1.2 +3 -5 xml-batik/sources/org/apache/batik/bridge/AbstractSVGGradientElementBridge.java Index: AbstractSVGGradientElementBridge.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/bridge/AbstractSVGGradientElementBridge.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- AbstractSVGGradientElementBridge.java 2001/05/02 14:33:32 1.1 +++ AbstractSVGGradientElementBridge.java 2001/07/11 12:23:55 1.2 @@ -29,7 +29,7 @@ * Bridge class for vending gradients. * * @author <a href="mailto:[EMAIL PROTECTED]">Thierry Kormann</a> - * @version $Id: AbstractSVGGradientElementBridge.java,v 1.1 2001/05/02 14:33:32 tkormann Exp $ + * @version $Id: AbstractSVGGradientElementBridge.java,v 1.2 2001/07/11 12:23:55 deweese Exp $ */ public abstract class AbstractSVGGradientElementBridge extends AbstractSVGBridge implements PaintBridge, ErrorConstants { @@ -233,10 +233,8 @@ stops = new LinkedList(); } if (previous != null) { - if (stop.offset == previous.offset) { - stops.removeLast(); - } else if (stop.offset < previous.offset) { - stop.offset = previous.offset+0.01f; + if (stop.offset < previous.offset) { + stop.offset = previous.offset; } } stops.add(stop); 1.7 +518 -1 xml-batik/sources/org/apache/batik/ext/awt/MultipleGradientPaintContext.java Index: MultipleGradientPaintContext.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/ext/awt/MultipleGradientPaintContext.java,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- MultipleGradientPaintContext.java 2001/04/30 22:01:00 1.6 +++ MultipleGradientPaintContext.java 2001/07/11 12:23:57 1.7 @@ -23,11 +23,13 @@ * * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans * @author <a href="mailto:[EMAIL PROTECTED]">Vincent Hardy</a> - * @version $Id: MultipleGradientPaintContext.java,v 1.6 2001/04/30 22:01:00 deweese Exp $ + * @version $Id: MultipleGradientPaintContext.java,v 1.7 2001/07/11 12:23:57 deweese Exp $ * */ abstract class MultipleGradientPaintContext implements PaintContext { + protected final static boolean DEBUG = false; + /** * The color model data is generated in (always un premult). */ @@ -104,6 +106,12 @@ */ protected int[][] gradients; + /** This holds the blend of all colors in the gradient. + * we use this at extreamly low resolutions to ensure we + * get a decent blend of the colors. + */ + protected int gradientAverage; + /** Length of the 2D slow lookup gradients array. */ protected int gradientsLength; @@ -412,6 +420,12 @@ int gradientsTot = 1; //the eventual size of the single array + // These are fixed point 8.16 (start with 0.5) + int aveA = 0x008000; + int aveR = 0x008000; + int aveG = 0x008000; + int aveB = 0x008000; + //for every interval (transition between 2 colors) for(int i=0; i < gradients.length; i++){ @@ -428,11 +442,24 @@ //fill this array with the colors in between rgb1 and rgb2 interpolate(rgb1, rgb2, gradients[i]); + // Calculate Average of two colors... + int argb = gradients[i][GRADIENT_SIZE/2]; + float norm = normalizedIntervals[i]; + aveA += (int)(((argb>> 8)&0xFF0000)*norm); + aveR += (int)(((argb )&0xFF0000)*norm); + aveG += (int)(((argb<< 8)&0xFF0000)*norm); + aveB += (int)(((argb<<16)&0xFF0000)*norm); + //if the colors are opaque, transparency should still be 0xff000000 transparencyTest &= rgb1; transparencyTest &= rgb2; } + gradientAverage = (((aveA & 0xFF0000)<< 8) | + ((aveR & 0xFF0000) ) | + ((aveG & 0xFF0000)>> 8) | + ((aveB & 0xFF0000)>>16)); + // Put all gradients in a single array gradient = new int[gradientsTot]; int curOffset = 0; @@ -494,6 +521,12 @@ int rgb1; //2 colors to interpolate int rgb2; + // These are fixed point 8.16 (start with 0.5) + int aveA = 0x008000; + int aveR = 0x008000; + int aveG = 0x008000; + int aveB = 0x008000; + //for every interval (transition between 2 colors) for(int i=0; i < gradients.length; i++){ @@ -507,11 +540,24 @@ //fill this array with the colors in between rgb1 and rgb2 interpolate(rgb1, rgb2, gradients[i]); + // Calculate Average of two colors... + int argb = gradients[i][GRADIENT_SIZE/2]; + float norm = normalizedIntervals[i]; + aveA += (int)(((argb>> 8)&0xFF0000)*norm); + aveR += (int)(((argb )&0xFF0000)*norm); + aveG += (int)(((argb<< 8)&0xFF0000)*norm); + aveB += (int)(((argb<<16)&0xFF0000)*norm); + //if the colors are opaque, transparency should still be 0xff000000 transparencyTest &= rgb1; transparencyTest &= rgb2; } + gradientAverage = (((aveA & 0xFF0000)<< 8) | + ((aveR & 0xFF0000) ) | + ((aveG & 0xFF0000)>> 8) | + ((aveB & 0xFF0000)>>16)); + //if interpolation occurred in Linear RGB space, convert the //gradients back to SRGB using the lookup table if (colorSpace == LinearGradientPaint.LINEAR_RGB) { @@ -761,6 +807,477 @@ return gradients[gradients.length - 1][GRADIENT_SIZE_INDEX]; } + + + /** Helper function to index into the gradients array. This is necessary + * because each interval has an array of colors with uniform size 255. + * However, the color intervals are not necessarily of uniform length, so + * a conversion is required. This version also does anti-aliasing by + * averaging the gradient over position+/-(sz/2). + * + * @param position the unmanipulated position. want to map this into the + * range 0 to 1 + * @param sz the size in gradient space to average. + * + * @returns ARGB integer color to display + */ + protected final int indexGradientAntiAlias(float position, float sz) { + + //first, manipulate position value depending on the cycle method. + if (cycleMethod == MultipleGradientPaint.NO_CYCLE) { + if (DEBUG) System.out.println("NO_CYCLE"); + float p1 = position-(sz/2); + float p2 = position+(sz/2); + + if (p1 > 1) { + if (isSimpleLookup) + return gradient[fastGradientArraySize]; + else + return gradients[gradients.length-1][GRADIENT_SIZE_INDEX]; + } + if (p2 < 0) { + if (isSimpleLookup) return gradient[0]; + else return gradients[0][0]; + } + int interior; + float top_weight=0, bottom_weight=0, frac; + if (p2 > 1) { + top_weight = (p2-1)/sz; + if (p1 <0) { + bottom_weight = -p1/sz; + frac=1; + interior = gradientAverage; + } else { + frac=1-p1; + interior = getAntiAlias(p1, true, 1, false, 1-p1, 1); + } + } else if (p1 < 0) { + bottom_weight = -p1/sz; + frac = p2; + interior = getAntiAlias(0, true, p2, false, p2, 1); + } else + return getAntiAlias(p1, true, p2, false, sz, 1); + + int norm = (int)((1<<16)*frac/sz); + int pA = (((interior>>>20)&0xFF0)*norm)>>16; + int pR = (((interior>> 12)&0xFF0)*norm)>>16; + int pG = (((interior>> 4)&0xFF0)*norm)>>16; + int pB = (((interior<< 4)&0xFF0)*norm)>>16; + + if (bottom_weight != 0) { + int bPix; + if (isSimpleLookup) bPix = gradient[0]; + else bPix = gradients[0][0]; + + // System.out.println("ave: " + gradientAverage); + norm = (int)((1<<16)*bottom_weight); + pA += (((bPix>>>20) & 0xFF0)*norm)>>16; + pR += (((bPix>> 12) & 0xFF0)*norm)>>16; + pG += (((bPix>> 4) & 0xFF0)*norm)>>16; + pB += (((bPix<< 4) & 0xFF0)*norm)>>16; + } + + if (top_weight != 0) { + int tPix; + if (isSimpleLookup) + tPix = gradient[fastGradientArraySize]; + else + tPix = gradients[gradients.length-1][GRADIENT_SIZE_INDEX]; + + norm = (int)((1<<16)*top_weight); + pA += (((tPix>>>20) & 0xFF0)*norm)>>16; + pR += (((tPix>> 12) & 0xFF0)*norm)>>16; + pG += (((tPix>> 4) & 0xFF0)*norm)>>16; + pB += (((tPix<< 4) & 0xFF0)*norm)>>16; + } + + return (((pA&0xFF0)<<20) | + ((pR&0xFF0)<<12) | + ((pG&0xFF0)<< 4) | + ((pB&0xFF0)>> 4)); + } + + // See how many times we are going to "wrap around" the gradient, + // array. + int intSz = (int)sz; + + float weight = 1f; + if (intSz != 0) { + // We need to make sure that sz is < 1.0 otherwise + // p1 and p2 my pass each other which will cause no end of + // trouble. + sz -= intSz; + weight = (1-sz)/(intSz+sz); + if (weight < 0.1) + // The part of the color from the location will be swamped + // by the averaged part of the gradient so just use the + // average color for the gradient. + return gradientAverage; + } + + // So close to full gradient just use the average value... + if (sz > 0.99) + return gradientAverage; + + // Go up and down from position by 1/2 sz. + float p1 = position-(sz/2); + float p2 = position+(sz/2); + if (DEBUG) System.out.println("P1: " + p1 + " P2: " + p2); + + // These indicate the direction to go from p1 and p2 when + // averaging... + boolean p1_up=true; + boolean p2_up=false; + + if (cycleMethod == MultipleGradientPaint.REPEAT) { + if (DEBUG) System.out.println("REPEAT"); + + // Get positions between -1 and 1 + p1=p1-(int)p1; + p2=p2-(int)p2; + + // force to be in rage 0-1. + if (p1 <0) p1 += 1; + if (p2 <0) p2 += 1; + } + + else { //cycleMethod == MultipleGradientPaint.REFLECT + if (DEBUG) System.out.println("REFLECT"); + + //take absolute values + // Note when we reflect we change sense of p1/2_up. + if (p2 < 0) { + p1 = -p1; p1_up = !p1_up; + p2 = -p2; p2_up = !p2_up; + } else if (p1 < 0) { + p1 = -p1; p1_up = !p1_up; + } + + int part1, part2; + part1 = (int)p1; // take the integer part + p1 = p1 - part1; // get the fractional part + + part2 = (int)p2; // take the integer part + p2 = p2 - part2; // get the fractional part + + // if integer part is odd we want the reflected color instead. + // Note when we reflect we change sense of p1/2_up. + if ((part1 & 0x01) == 1) { + p1 = 1-p1; + p1_up = !p1_up; + } + + if ((part2 & 0x01) == 1) { + p2 = 1-p2; + p2_up = !p2_up; + } + + // Check if in the end they just got switched around. + // this commonly happens if they both end up negative. + if ((p1 > p2) && !p1_up && p2_up) { + float t = p1; + p1 = p2; + p2 = t; + p1_up = true; + p2_up = false; + } + } + + return getAntiAlias(p1, p1_up, p2, p2_up, sz, weight); + } + + + private final int getAntiAlias(float p1, boolean p1_up, + float p2, boolean p2_up, + float sz, float weight) { + + // Until the last set of ops these are 28.4 fixed point values. + int ach=0, rch=0, gch=0, bch=0; + if (isSimpleLookup) { + p1 *= fastGradientArraySize; + p2 *= fastGradientArraySize; + + int idx1 = (int)p1; + int idx2 = (int)p2; + + // Simpliest case we just take the average value. + // Note that this may not be correct in all cases, + // but saves us always doing the summation between idx1 and idx2. + if ((idx1 <= idx2) && p1_up && !p2_up) + return gradient[(idx1+idx2)>>1]; + + if (DEBUG) System.out.println( "P1: " + p1 + " " + p1_up + + " P2: " + p2 + " " + p2_up); + + // Do the bulk of the work, all the whole gradient entries + // for idx1 and idx2. + int pix, norm; + if (p1_up) { + for (int i=idx1+1; i<fastGradientArraySize; i++) { + pix = gradient[i]; + ach += ((pix>>>20)&0xFF0); + rch += ((pix>>>12)&0xFF0); + gch += ((pix>>> 4)&0xFF0); + bch += ((pix<< 4)&0xFF0); + } + } else { + for (int i=0; i<idx1; i++) { + pix = gradient[i]; + ach += ((pix>>>20)&0xFF0); + rch += ((pix>>>12)&0xFF0); + gch += ((pix>>> 4)&0xFF0); + bch += ((pix<< 4)&0xFF0); + } + } + + if (p2_up) { + for (int i=idx2+1; i<fastGradientArraySize; i++) { + pix = gradient[i]; + ach += ((pix>>>20)&0xFF0); + rch += ((pix>>>12)&0xFF0); + gch += ((pix>>> 4)&0xFF0); + bch += ((pix<< 4)&0xFF0); + } + } else { + for (int i=0; i<idx2; i++) { + pix = gradient[i]; + ach += ((pix>>>20)&0xFF0); + rch += ((pix>>>12)&0xFF0); + gch += ((pix>>> 4)&0xFF0); + bch += ((pix<< 4)&0xFF0); + } + } + + // Normalize the summation so far... + int isz = (int)((1<<16)/(sz*fastGradientArraySize)); + ach = (ach*isz)>>16; + rch = (rch*isz)>>16; + gch = (gch*isz)>>16; + bch = (bch*isz)>>16; + + // Clean up with the partial buckets at each end. + if (p1_up) norm = (int)(((1-(p1-idx1))*(1<<16)) + /(sz*fastGradientArraySize)); + else norm = (int)(((p1-idx1)*(1<<16)) + /(sz*fastGradientArraySize)); + pix = gradient[idx1]; + ach += (((pix>>>20)&0xFF0) *norm)>>16; + rch += (((pix>>>12)&0xFF0) *norm)>>16; + gch += (((pix>>> 4)&0xFF0) *norm)>>16; + bch += (((pix<< 4)&0xFF0) *norm)>>16; + + if (p2_up) norm = (int)(((1-(p2-idx2))*(1<<16)) + /(sz*fastGradientArraySize)); + else norm = (int)(((p2-idx2)*(1<<16)) + /(sz*fastGradientArraySize)); + pix = gradient[idx2]; + ach += (((pix>>>20)&0xFF0) *norm)>>16; + rch += (((pix>>>12)&0xFF0) *norm)>>16; + gch += (((pix>>> 4)&0xFF0) *norm)>>16; + bch += (((pix<< 4)&0xFF0) *norm)>>16; + + // Round and drop the 4bits frac. + ach = (ach+0x08)>>4; + rch = (rch+0x08)>>4; + gch = (gch+0x08)>>4; + bch = (bch+0x08)>>4; + + } else { + int idx1=0, idx2=0; + int i1=-1, i2=-1; + float f1=0, f2=0; + // Find which gradient interval our points fall into. + for (int i = 0; i < gradientsLength; i++) { + if ((p1 < fractions[i+1]) && (i1 == -1)) { + //this is the array we want + i1 = i; + f1 = p1 - fractions[i]; + + f1 = ((f1/normalizedIntervals[i]) + *GRADIENT_SIZE_INDEX); + //this is the interval we want. + idx1 = (int)f1; + if (i2 != -1) break; + } + if ((p2 < fractions[i+1]) && (i2 == -1)) { + //this is the array we want + i2 = i; + f2 = p2 - fractions[i]; + + f2 = ((f2/normalizedIntervals[i]) + *GRADIENT_SIZE_INDEX); + //this is the interval we want. + idx2 = (int)f2; + if (i1 != -1) break; + } + } + + if (i1 == -1) { + i1 = gradients.length - 1; + f1 = idx1 = GRADIENT_SIZE_INDEX; + } + + if (i2 == -1) { + i2 = gradients.length - 1; + f2 = idx2 = GRADIENT_SIZE_INDEX; + } + + if (DEBUG) System.out.println("I1: " + i1 + " Idx1: " + idx1 + + " I2: " + i2 + " Idx2: " + idx2); + + // Simple case within one gradient array (so the average + // of the two idx gives us the true average of colors). + if ((i1 == i2) && (idx1 <= idx2) && p1_up && !p2_up) + return gradients[i1][(idx1+idx2+1)>>1]; + + // i1 != i2 + + int pix, norm; + int base = (int)((1<<16)/sz); + if ((i1 < i2) && p1_up && !p2_up) { + norm = (int)((base + *normalizedIntervals[i1] + *(GRADIENT_SIZE_INDEX-f1)) + /GRADIENT_SIZE_INDEX); + pix = gradients[i1][(idx1+GRADIENT_SIZE)>>1]; + ach += (((pix>>>20)&0xFF0) *norm)>>16; + rch += (((pix>>>12)&0xFF0) *norm)>>16; + gch += (((pix>>> 4)&0xFF0) *norm)>>16; + bch += (((pix<< 4)&0xFF0) *norm)>>16; + + for (int i=i1+1; i<i2; i++) { + norm = (int)(base*normalizedIntervals[i]); + pix = gradients[i][GRADIENT_SIZE>>1]; + + ach += (((pix>>>20)&0xFF0) *norm)>>16; + rch += (((pix>>>12)&0xFF0) *norm)>>16; + gch += (((pix>>> 4)&0xFF0) *norm)>>16; + bch += (((pix<< 4)&0xFF0) *norm)>>16; + } + + norm = (int)((base*normalizedIntervals[i2]*f2) + /GRADIENT_SIZE_INDEX); + pix = gradients[i2][(idx2+1)>>1]; + ach += (((pix>>>20)&0xFF0) *norm)>>16; + rch += (((pix>>>12)&0xFF0) *norm)>>16; + gch += (((pix>>> 4)&0xFF0) *norm)>>16; + bch += (((pix<< 4)&0xFF0) *norm)>>16; + } else { + if (p1_up) { + norm = (int)((base + *normalizedIntervals[i1] + *(GRADIENT_SIZE_INDEX-f1)) + /GRADIENT_SIZE_INDEX); + pix = gradients[i1][(idx1+GRADIENT_SIZE)>>1]; + } else { + norm = (int)((base*normalizedIntervals[i1]*f1) + /GRADIENT_SIZE_INDEX); + pix = gradients[i1][(idx1+1)>>1]; + } + ach += (((pix>>>20)&0xFF0) *norm)>>16; + rch += (((pix>>>12)&0xFF0) *norm)>>16; + gch += (((pix>>> 4)&0xFF0) *norm)>>16; + bch += (((pix<< 4)&0xFF0) *norm)>>16; + + if (p2_up) { + norm = (int)((base + *normalizedIntervals[i2] + *(GRADIENT_SIZE_INDEX-f2)) + /GRADIENT_SIZE_INDEX); + pix = gradients[i2][(idx2+GRADIENT_SIZE)>>1]; + } else { + norm = (int)((base*normalizedIntervals[i2]*f2) + /GRADIENT_SIZE_INDEX); + pix = gradients[i2][(idx2+1)>>1]; + } + ach += (((pix>>>20)&0xFF0) *norm)>>16; + rch += (((pix>>>12)&0xFF0) *norm)>>16; + gch += (((pix>>> 4)&0xFF0) *norm)>>16; + bch += (((pix<< 4)&0xFF0) *norm)>>16; + + if (p1_up) { + for (int i=i1+1; i<gradientsLength; i++) { + norm = (int)(base*normalizedIntervals[i]); + pix = gradients[i][GRADIENT_SIZE>>1]; + + ach += (((pix>>>20)&0xFF0) *norm)>>16; + rch += (((pix>>>12)&0xFF0) *norm)>>16; + gch += (((pix>>> 4)&0xFF0) *norm)>>16; + bch += (((pix<< 4)&0xFF0) *norm)>>16; + } + } else { + for (int i=0; i<i1; i++) { + norm = (int)(base*normalizedIntervals[i]); + pix = gradients[i][GRADIENT_SIZE>>1]; + + ach += (((pix>>>20)&0xFF0) *norm)>>16; + rch += (((pix>>>12)&0xFF0) *norm)>>16; + gch += (((pix>>> 4)&0xFF0) *norm)>>16; + bch += (((pix<< 4)&0xFF0) *norm)>>16; + } + } + + if (p2_up) { + for (int i=i2+1; i<gradientsLength; i++) { + norm = (int)(base*normalizedIntervals[i]); + pix = gradients[i][GRADIENT_SIZE>>1]; + + ach += (((pix>>>20)&0xFF0) *norm)>>16; + rch += (((pix>>>12)&0xFF0) *norm)>>16; + gch += (((pix>>> 4)&0xFF0) *norm)>>16; + bch += (((pix<< 4)&0xFF0) *norm)>>16; + } + } else { + for (int i=0; i<i2; i++) { + norm = (int)(base*normalizedIntervals[i]); + pix = gradients[i][GRADIENT_SIZE>>1]; + + ach += (((pix>>>20)&0xFF0) *norm)>>16; + rch += (((pix>>>12)&0xFF0) *norm)>>16; + gch += (((pix>>> 4)&0xFF0) *norm)>>16; + bch += (((pix<< 4)&0xFF0) *norm)>>16; + } + } + + } + ach = (ach+0x08)>>4; + rch = (rch+0x08)>>4; + gch = (gch+0x08)>>4; + bch = (bch+0x08)>>4; + if (DEBUG) System.out.println("Pix: [" + ach + ", " + rch + + ", " + gch + ", " + bch + "]"); + } + + if (weight != 1) { + // System.out.println("ave: " + gradientAverage); + int aveW = (int)((1<<16)*(1-weight)); + int aveA = ((gradientAverage>>>24) & 0xFF)*aveW; + int aveR = ((gradientAverage>> 16) & 0xFF)*aveW; + int aveG = ((gradientAverage>> 8) & 0xFF)*aveW; + int aveB = ((gradientAverage ) & 0xFF)*aveW; + + int iw = (int)(weight*(1<<16)); + ach = ((ach*iw)+aveA)>>16; + rch = ((rch*iw)+aveR)>>16; + gch = ((gch*iw)+aveG)>>16; + bch = ((bch*iw)+aveB)>>16; + } + // If any high bits are set we are not in range. + // If the highest bit is set then we are negative so + // clamp to zero else we are > 255 so clamp to 255. + if ((ach & 0xFFFFFF00) != 0) + ach = ((ach & 0x80000000) != 0)?0:255; + if ((rch & 0xFFFFFF00) != 0) + rch = ((rch & 0x80000000) != 0)?0:255; + if ((gch & 0xFFFFFF00) != 0) + gch = ((gch & 0x80000000) != 0)?0:255; + if ((bch & 0xFFFFFF00) != 0) + bch = ((bch & 0x80000000) != 0)?0:255; + + + return ((ach<<24) | (rch<<16) | (gch<<8) | bch); + } + /** Helper function to convert a color component in sRGB space to linear * RGB space. Used to build a static lookup table. 1.4 +22 -12 xml-batik/sources/org/apache/batik/ext/awt/RadialGradientPaintContext.java Index: RadialGradientPaintContext.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/ext/awt/RadialGradientPaintContext.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- RadialGradientPaintContext.java 2001/04/27 19:53:40 1.3 +++ RadialGradientPaintContext.java 2001/07/11 12:23:58 1.4 @@ -21,11 +21,13 @@ * * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans * @author <a href="mailto:[EMAIL PROTECTED]">Vincent Hardy</a> - * @version $Id: RadialGradientPaintContext.java,v 1.3 2001/04/27 19:53:40 deweese Exp $ + * @version $Id: RadialGradientPaintContext.java,v 1.4 2001/07/11 12:23:58 deweese Exp $ * */ final class RadialGradientPaintContext extends MultipleGradientPaintContext { + private static final boolean USE_ANTI_ALIAS = false; + /** True when (focus == center) */ private boolean isSimpleFocus = false; @@ -418,6 +420,8 @@ int indexer = off; //index variable for pixels array int i, j; //indexing variables for FOR loops int pixInc = w+adjust;//incremental index change for pixels array + + float delta, pixSzSq = (float)(a00*a00+a01*a01+a10*a10+a11*a11); for (j = 0; j < h; j++) { //for every row @@ -427,8 +431,9 @@ //for every column (inner loop begins here) for (i = 0; i < w; i++) { - // special case to avoid divide by zero - if (X == focusX) { + // special case to avoid divide by zero or very near zero + if (((X-focusX)>-0.000001) && + ((X-focusX)< 0.000001)) { solutionX = focusX; solutionY = centerY; @@ -469,28 +474,33 @@ //intersection point to the focus. Want the squares so we can //do 1 square root after division instead of 2 before. - deltaXSq = X - focusX; + deltaXSq = (float)solutionX - focusX; deltaXSq = deltaXSq * deltaXSq; - deltaYSq = Y - focusY; + deltaYSq = (float)solutionY - focusY; deltaYSq = deltaYSq * deltaYSq; - currentToFocusSq = deltaXSq + deltaYSq; + intersectToFocusSq = deltaXSq + deltaYSq; - deltaXSq = (float)solutionX - focusX; + deltaXSq = X - focusX; deltaXSq = deltaXSq * deltaXSq; - deltaYSq = (float)solutionY - focusY; + deltaYSq = Y - focusY; deltaYSq = deltaYSq * deltaYSq; - intersectToFocusSq = deltaXSq + deltaYSq; + currentToFocusSq = deltaXSq + deltaYSq; //want the percentage (0-1) of the current point along the //focus-circumference line g = (float)Math.sqrt(currentToFocusSq / intersectToFocusSq); - - //save the color at this point - pixels[indexer + i] = indexIntoGradientsArrays(g); + + //Get the color at this point + if (USE_ANTI_ALIAS) { + delta = (float)Math.sqrt(pixSzSq/intersectToFocusSq); + pixels[indexer + i] = indexGradientAntiAlias(g, delta); + } else { + pixels[indexer + i] = indexIntoGradientsArrays(g); + } X += a00; //incremental change in X, Y Y += a10; 1.6 +3 -1 xml-batik/sources/org/apache/batik/util/ParsedURL.java Index: ParsedURL.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/util/ParsedURL.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- ParsedURL.java 2001/05/03 22:11:04 1.5 +++ ParsedURL.java 2001/07/11 12:23:59 1.6 @@ -259,7 +259,9 @@ /** * Returns the path for this URL, if any (where appropriate for - * the protocol this also includes the file, not just directory.) + * the protocol this also includes the file, not just directory). + * Note that getPath appears in JDK 1.3 as a synonym for getFile + * from JDK 1.2. */ public String getPath() { if (data.path == null) return null; 1.2 +1 -1 xml-batik/sources/org/apache/batik/util/ParsedURLData.java Index: ParsedURLData.java =================================================================== RCS file: /home/cvs/xml-batik/sources/org/apache/batik/util/ParsedURLData.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- ParsedURLData.java 2001/05/03 22:11:05 1.1 +++ ParsedURLData.java 2001/07/11 12:24:00 1.2 @@ -83,7 +83,7 @@ port = url.getPort(); - path = url.getPath(); + path = url.getFile(); if ((path != null) && (path.length() == 0)) path = null; 1.1 xml-batik/samples/tests/radialGradient2.svg Index: radialGradient2.svg =================================================================== <?xml version="1.0" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20000802//EN" "http://www.w3.org/TR/2000/CR-SVG-20000802/DTD/svg-20000802.dtd"> <!-- ========================================================================= --> <!-- Copyright (C) The Apache Software Foundation. All rights reserved. --> <!-- --> <!-- This software is published under the terms of the Apache Software License --> <!-- version 1.1, a copy of which has been included with this distribution in --> <!-- the LICENSE file. --> <!-- ========================================================================= --> <!-- ========================================================================= --> <!-- @author [EMAIL PROTECTED] --> <!-- @version $Id: radialGradient2.svg,v 1.1 2001/07/11 12:24:01 deweese Exp $ --> <!-- ========================================================================= --> <?xml-stylesheet type="text/css" href="test.css" ?> <svg id="body" width="450" height="500" viewBox="0 0 450 500"> <title><radialGradient> Test A</title> <text class="title" x="50%" y="40"><radialGradient> Test</text> <defs> <!-- Shape filled by radial gradients --> <g id="testShape"> <rect x="-25" y="-20" width="50" height="40" /> </g> <!-- ========================================== --> <!-- Two gradients, one with no values defined --> <!-- and one with the default values specified --> <!-- They should create the same pattern --> <!-- ========================================== --> <radialGradient id="rgDefaults"> <stop offset=".0" stop-color="gold" /> <stop offset=".5" stop-color="crimson" /> <stop offset=".5" stop-color="gold" /> <stop offset="1." stop-color="crimson" /> </radialGradient> <radialGradient id="rgSpecifiedDefaults" gradientUnits="objectBoundingBox" cx="50%" cy="50%" r="50%" fx="50%" fy="50%" spreadMethod="pad" xlink:href="#rgDefaults" /> <!-- ========================================== --> <!-- gradientUnits. The following gradients --> <!-- is defined so as to produce the same --> <!-- result as with the default settings --> <!-- For example, cx default is 50% in object --> <!-- bounding box, which is .5*50 = 25 --> <!-- r = sqrt(50*50 + 40*40) = 22.63846284534354156643452041746 --> <!-- ========================================== --> <radialGradient id="rgUserSpaceOnUse" cx="0" cy="0" r="22.63846284534354156643452041746" fx="0" fy="0" xlink:href="#rdDefaults" /> <radialGradient id="rgCxCyA" xlink:href="#rgDefaults" cx="0%" cy="100%"> </radialGradient> <radialGradient id="rgCxCyB" xlink:href="#rgDefaults" cx="75%" cy="25%"> </radialGradient> <radialGradient id="rgFxFyA" xlink:href="#rgCxCyA" fx="0%" fy="100%"> </radialGradient> <radialGradient id="rgFxFyB" xlink:href="#rgDefaults" fx="60%" fy="40%"> </radialGradient> <radialGradient id="rgFxFyC" xlink:href="#rgDefaults" fx="0%" fy="50%"> </radialGradient> <radialGradient id="rgFxFyD" xlink:href="#rgDefaults" fx="0%" fy="0%"> </radialGradient> <radialGradient id="rgSpreadA" xlink:href="#rgDefaults" r=".125"> </radialGradient> <radialGradient id="rgSpreadB" xlink:href="#rgDefaults" r=".125" spreadMethod="reflect"> </radialGradient> <radialGradient id="rgSpreadC" xlink:href="#rgDefaults" r=".125" spreadMethod="repeat"> </radialGradient> <radialGradient id="rgTxfA" xlink:href="#rgDefaults" gradientTransform="translate(.5, .5)" /> <radialGradient id="rgTxfB" xlink:href="#rgDefaults" cx="0%" cy="0%" gradientTransform="translate(.5, .5)" /> <radialGradient id="rgTxfC" xlink:href="#rgDefaults" cx="0%" cy="0%" gradientTransform="translate(.5, .5) scale(.25, 1.5)" /> <radialGradient id="rgTxfD" xlink:href="#rgFxFyD" gradientTransform="scale(.5, .5)" /> </defs> <g class="legend"> <g transform="translate(70, 0)"> <g transform="translate(0, 100)"> <use xlink:href="#testShape" fill="url(#rgDefaults)" /> <text y="-30">Defaults</text> </g> <g transform="translate(0, 170)"> <use xlink:href="#testShape" fill="url(#rgSpecifiedDefaults)" /> <text y="-30">Forced Defaults</text> </g> <g transform="translate(0, 240)"> <use xlink:href="#testShape" fill="url(#rgSpecifiedDefaults)" /> <text y="-30">userSpaceOnUse</text> </g> <g transform="translate(0, 310)"> <use xlink:href="#testShape" fill="url(#rgCxCyA)" /> <text y="-30">(cx,cy) = (0%, 100%)</text> </g> <g transform="translate(0, 380)"> <use xlink:href="#testShape" fill="url(#rgCxCyB)" /> <text y="-30">(cx,cy) = (75%, 25%)</text> </g> </g> <g transform="translate(200, 0)"> <g transform="translate(0, 100)"> <use xlink:href="#testShape" fill="url(#rgFxFyB)" /> <text y="-30">(fx,fy)=(60%,40%)</text> </g> <g transform="translate(0, 170)"> <use xlink:href="#testShape" fill="url(#rgFxFyC)" /> <text y="-30">(fx,fy)=(0%,50%)</text> </g> <g transform="translate(0, 240)"> <use xlink:href="#testShape" fill="url(#rgFxFyD)" /> <text y="-30">(fx,fy)=(0%,0%)</text> </g> <g transform="translate(0, 310)"> <use xlink:href="#testShape" fill="url(#rgSpreadA)" /> <text y="-30">r=.125, spread=default</text> </g> <g transform="translate(0, 380)"> <use xlink:href="#testShape" fill="url(#rgSpreadB)" /> <text y="-30">r=.125, spread=reflect</text> </g> <g transform="translate(0, 450)"> <use xlink:href="#testShape" fill="url(#rgSpreadC)" /> <text y="-30">r=.125, spread=repeat</text> </g> </g> <g transform="translate(330, 0)"> <g transform="translate(0, 100)"> <use xlink:href="#testShape" fill="url(#rgTxfA)" /> <text y="-30">translate(.5,.5)</text> </g> <g transform="translate(0, 170)"> <use xlink:href="#testShape" fill="url(#rgTxfB)" /> <text y="-30">(cx,cy)=(0%,0%) translate(.5,.5)</text> </g> <g transform="translate(0, 240)"> <use xlink:href="#testShape" fill="url(#rgTxfC)" /> <text y="-30">scale(.25,.5)</text> </g> <g transform="translate(0, 310)"> <use xlink:href="#testShape" fill="url(#rgTxfD)" /> <text y="-30">(fx,fy)=(0,0) scale(.5, .5)</text> </g> <g transform="translate(0, 380)"> <use xlink:href="#testShape" fill="url(#rgFxFyA)" /> <text y="-30">(fx,fy)=(cx, cy)=(0%, 100%)</text> </g> </g> </g> </svg> --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]