KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > ext > awt > LinearGradientPaintContext


1 /*
2
3    Copyright 2001-2004 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17  */

18 package org.apache.batik.ext.awt;
19
20 import java.awt.Color JavaDoc;
21 import java.awt.Rectangle JavaDoc;
22 import java.awt.RenderingHints JavaDoc;
23 import java.awt.geom.AffineTransform JavaDoc;
24 import java.awt.geom.NoninvertibleTransformException JavaDoc;
25 import java.awt.geom.Point2D JavaDoc;
26 import java.awt.geom.Rectangle2D JavaDoc;
27 import java.awt.image.ColorModel JavaDoc;
28
29 /**
30  * Provides the actual implementation for the LinearGradientPaint
31  * This is where the pixel processing is done.
32  *
33  * @author Nicholas Talian, Vincent Hardy, Jim Graham, Jerry Evans
34  * @author <a HREF="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
35  * @version $Id: LinearGradientPaintContext.java,v 1.13 2005/03/27 08:58:32 cam Exp $
36  * @see java.awt.PaintContext
37  * @see java.awt.Paint
38  * @see java.awt.GradientPaint
39  */

40 final class LinearGradientPaintContext extends MultipleGradientPaintContext {
41     
42     /**
43      * The following invariants are used to process the gradient value from
44      * a device space coordinate, (X, Y):
45      * g(X, Y) = dgdX*X + dgdY*Y + gc
46      */

47     private float dgdX, dgdY, gc, pixSz;
48            
49     private static final int DEFAULT_IMPL = 1;
50     private static final int ANTI_ALIAS_IMPL = 3;
51
52     private int fillMethod;
53
54     /**
55      * Constructor for LinearGradientPaintContext.
56      *
57      * @param cm {@link ColorModel} that receives
58      * the <code>Paint</code> data. This is used only as a hint.
59      *
60      * @param deviceBounds the device space bounding box of the
61      * graphics primitive being rendered
62      *
63      * @param userBounds the user space bounding box of the
64      * graphics primitive being rendered
65      *
66      * @param t the {@link AffineTransform} from user
67      * space into device space (gradientTransform should be
68      * concatenated with this)
69      *
70      * @param hints the hints that the context object uses to choose
71      * between rendering alternatives
72      *
73      * @param dStart gradient start point, in user space
74      *
75      * @param dEnd gradient end point, in user space
76      *
77      * @param fractions the fractions specifying the gradient distribution
78      *
79      * @param colors the gradient colors
80      *
81      * @param cycleMethod either NO_CYCLE, REFLECT, or REPEAT
82      *
83      * @param colorSpace which colorspace to use for interpolation,
84      * either SRGB or LINEAR_RGB
85      *
86      */

87     public LinearGradientPaintContext(ColorModel JavaDoc cm,
88                                       Rectangle JavaDoc deviceBounds,
89                                       Rectangle2D JavaDoc userBounds,
90                                       AffineTransform JavaDoc t,
91                                       RenderingHints JavaDoc hints,
92                                       Point2D JavaDoc dStart,
93                                       Point2D JavaDoc dEnd,
94                                       float[] fractions,
95                                       Color JavaDoc[] colors,
96                                       MultipleGradientPaint.CycleMethodEnum
97                                       cycleMethod,
98                                       MultipleGradientPaint.ColorSpaceEnum
99                                       colorSpace)
100         throws NoninvertibleTransformException JavaDoc
101     {
102         super(cm, deviceBounds, userBounds, t, hints, fractions,
103               colors, cycleMethod, colorSpace);
104         
105         // Use single precision floating points
106
Point2D.Float JavaDoc start = new Point2D.Float JavaDoc((float)dStart.getX(),
107                                                 (float)dStart.getY());
108         Point2D.Float JavaDoc end = new Point2D.Float JavaDoc((float)dEnd.getX(),
109                                               (float)dEnd.getY());
110         
111         // A given point in the raster should take on the same color as its
112
// projection onto the gradient vector.
113
// Thus, we want the projection of the current position vector
114
// onto the gradient vector, then normalized with respect to the
115
// length of the gradient vector, giving a value which can be mapped into
116
// the range 0-1.
117
// projection = currentVector dot gradientVector / length(gradientVector)
118
// normalized = projection / length(gradientVector)
119

120         float dx = end.x - start.x; // change in x from start to end
121
float dy = end.y - start.y; // change in y from start to end
122
float dSq = dx*dx + dy*dy; // total distance squared
123

124         //avoid repeated calculations by doing these divides once.
125
float constX = dx/dSq;
126         float constY = dy/dSq;
127     
128         //incremental change along gradient for +x
129
dgdX = a00*constX + a10*constY;
130         //incremental change along gradient for +y
131
dgdY = a01*constX + a11*constY;
132         
133         float dgdXAbs = Math.abs(dgdX);
134         float dgdYAbs = Math.abs(dgdY);
135         if (dgdXAbs > dgdYAbs) pixSz = dgdXAbs;
136         else pixSz = dgdYAbs;
137
138         //constant, incorporates the translation components from the matrix
139
gc = (a02-start.x)*constX + (a12-start.y)*constY;
140
141         Object JavaDoc colorRend = hints.get(RenderingHints.KEY_COLOR_RENDERING);
142         Object JavaDoc rend = hints.get(RenderingHints.KEY_RENDERING);
143
144         fillMethod = DEFAULT_IMPL;
145
146         if ((cycleMethod == MultipleGradientPaint.REPEAT) ||
147             hasDiscontinuity) {
148             if (rend == RenderingHints.VALUE_RENDER_QUALITY)
149                 fillMethod = ANTI_ALIAS_IMPL;
150             // ColorRend overrides rend.
151
if (colorRend == RenderingHints.VALUE_COLOR_RENDER_SPEED)
152                 fillMethod = DEFAULT_IMPL;
153             else if (colorRend == RenderingHints.VALUE_COLOR_RENDER_QUALITY)
154                 fillMethod = ANTI_ALIAS_IMPL;
155         }
156     }
157
158     protected void fillHardNoCycle(int[] pixels, int off, int adjust,
159                               int x, int y, int w, int h) {
160
161         //constant which can be pulled out of the inner loop
162
final float initConst = (dgdX*x) + gc;
163
164         for(int i=0; i<h; i++) { //for every row
165
//initialize current value to be start.
166
float g = initConst + dgdY*(y+i);
167             final int rowLimit = off+w; // end of row iteration
168

169             if (dgdX == 0) {
170                 // System.out.println("In fillHard: " + g);
171
final int val;
172                 if (g <= 0)
173                     val = gradientUnderflow;
174                 else if (g >= 1)
175                     val = gradientOverflow;
176                 else {
177                     // Could be a binary search...
178
int gradIdx = 0;
179                     while (gradIdx < gradientsLength-1) {
180                         if (g < fractions[gradIdx+1])
181                             break;
182                         gradIdx++;
183                     }
184                     float delta = (g-fractions[gradIdx]);
185                     float idx = ((delta*GRADIENT_SIZE_INDEX)
186                                   /normalizedIntervals[gradIdx])+0.5f;
187                     val = gradients[gradIdx][(int)idx];
188                 }
189
190                 while (off < rowLimit) {
191                     pixels[off++] = val;
192                 }
193             } else {
194                 // System.out.println("In fillHard2: " + g);
195
int gradSteps;
196                 int preGradSteps;
197                 final int preVal, postVal;
198
199                 float gradStepsF;
200                 float preGradStepsF;
201                 if (dgdX >= 0) {
202                     gradStepsF = ((1-g)/dgdX);
203                     preGradStepsF = (float)Math.ceil((0-g)/dgdX);
204                     preVal = gradientUnderflow;
205                     postVal = gradientOverflow;
206                 } else { // dgdX < 0
207
gradStepsF = ((0-g)/dgdX);
208                     preGradStepsF = (float)Math.ceil((1-g)/dgdX);
209                     preVal = gradientOverflow;
210                     postVal = gradientUnderflow;
211                 }
212
213                 if (gradStepsF > w) gradSteps = w;
214                 else gradSteps = (int)gradStepsF;
215                 if (preGradStepsF > w) preGradSteps = w;
216                 else preGradSteps = (int)preGradStepsF;
217
218                 final int gradLimit = off + gradSteps;
219                 if (preGradSteps > 0) {
220                     final int preGradLimit = off + preGradSteps;
221
222                     while (off < preGradLimit) {
223                         pixels[off++] = preVal;
224                     }
225                     g += dgdX*preGradSteps;
226                 }
227                         
228                 if (dgdX > 0) {
229                     // Could be a binary search...
230
int gradIdx = 0;
231                     while (gradIdx < gradientsLength-1) {
232                         if (g < fractions[gradIdx+1])
233                             break;
234                         gradIdx++;
235                     }
236                     
237                     while (off < gradLimit) {
238                         float delta = (g-fractions[gradIdx]);
239                         final int [] grad = gradients[gradIdx];
240
241                         double stepsD = Math.ceil
242                             ((fractions[gradIdx+1]-g)/dgdX);
243                         int steps;
244                         if (stepsD > w) steps = w;
245                         else steps = (int)stepsD;
246                         int subGradLimit = off + steps;
247                         if (subGradLimit > gradLimit)
248                             subGradLimit = gradLimit;
249
250                         int idx = (int)(((delta*GRADIENT_SIZE_INDEX)
251                                           /normalizedIntervals[gradIdx])
252                                          *(1<<16)) + (1<<15);
253                         int step = (int)(((dgdX*GRADIENT_SIZE_INDEX)
254                                           /normalizedIntervals[gradIdx])
255                                          *(1<<16));
256                         while (off < subGradLimit) {
257                             pixels[off++] = grad[idx>>16];
258                             idx += step;
259                         }
260                         g+=dgdX*stepsD;
261                         gradIdx++;
262                     }
263                 } else {
264                     // Could be a binary search...
265
int gradIdx = gradientsLength-1;
266                     while (gradIdx > 0) {
267                         if (g > fractions[gradIdx])
268                             break;
269                         gradIdx--;
270                     }
271                     
272                     while (off < gradLimit) {
273                         float delta = (g-fractions[gradIdx]);
274                         final int [] grad = gradients[gradIdx];
275
276                         double stepsD = Math.ceil(delta/-dgdX);
277                         int steps;
278                         if (stepsD > w) steps = w;
279                         else steps = (int)stepsD;
280                         int subGradLimit = off + steps;
281                         if (subGradLimit > gradLimit)
282                             subGradLimit = gradLimit;
283
284                         int idx = (int)(((delta*GRADIENT_SIZE_INDEX)
285                                           /normalizedIntervals[gradIdx])
286                                          *(1<<16)) + (1<<15);
287                         int step = (int)(((dgdX*GRADIENT_SIZE_INDEX)
288                                           /normalizedIntervals[gradIdx])
289                                          *(1<<16));
290                         while (off < subGradLimit) {
291                             pixels[off++] = grad[idx>>16];
292                             idx += step;
293                         }
294                         g+=dgdX*stepsD;
295                         gradIdx--;
296                     }
297                 }
298
299                 while (off < rowLimit) {
300                     pixels[off++] = postVal;
301                 }
302             }
303             off += adjust; //change in off from row to row
304
}
305     }
306
307     protected void fillSimpleNoCycle(int[] pixels, int off, int adjust,
308                                 int x, int y, int w, int h) {
309         //constant which can be pulled out of the inner loop
310
final float initConst = (dgdX*x) + gc;
311         final float step = dgdX*fastGradientArraySize;
312         final int fpStep = (int)(step*(1<<16)); // fix point step
313

314         final int [] grad = gradient;
315
316         for(int i=0; i<h; i++){ //for every row
317
//initialize current value to be start.
318
float g = initConst + dgdY*(y+i);
319             g *= fastGradientArraySize;
320             g += 0.5; // rounding factor...
321

322             final int rowLimit = off+w; // end of row iteration
323

324             float check = dgdX*fastGradientArraySize*w;
325             if (check < 0) check = -check;
326             if (check < .3) {
327                 // System.out.println("In fillSimpleNC: " + g);
328
final int val;
329                 if (g<=0)
330                     val = gradientUnderflow;
331                 else if (g>=fastGradientArraySize)
332                     val = gradientOverflow;
333                 else
334                     val = grad[(int)g];
335                 while (off < rowLimit) {
336                     pixels[off++] = val;
337                 }
338             } else {
339                 // System.out.println("In fillSimpleNC2: " + g);
340
int gradSteps;
341                 int preGradSteps;
342                 final int preVal, postVal;
343                 if (dgdX > 0) {
344                     gradSteps = (int)((fastGradientArraySize-g)/step);
345                     preGradSteps = (int)Math.ceil(0-g/step);
346                     preVal = gradientUnderflow;
347                     postVal = gradientOverflow;
348
349                 } else { // dgdX < 0
350
gradSteps = (int)((0-g)/step);
351                     preGradSteps =
352                         (int)Math.ceil((fastGradientArraySize-g)/step);
353                     preVal = gradientOverflow;
354                     postVal = gradientUnderflow;
355                 }
356
357                 if (gradSteps > w)
358                     gradSteps = w;
359                 final int gradLimit = off + gradSteps;
360
361                 if (preGradSteps > 0) {
362                     if (preGradSteps > w)
363                         preGradSteps = w;
364                     final int preGradLimit = off + preGradSteps;
365
366                     while (off < preGradLimit) {
367                         pixels[off++] = preVal;
368                     }
369                     g += step*preGradSteps;
370                 }
371                         
372                 int fpG = (int)(g*(1<<16));
373                 while (off < gradLimit) {
374                     pixels[off++] = grad[fpG>>16];
375                     fpG += fpStep;
376                 }
377                         
378                 while (off < rowLimit) {
379                     pixels[off++] = postVal;
380                 }
381             }
382             off += adjust; //change in off from row to row
383
}
384     }
385     
386     protected void fillSimpleRepeat(int[] pixels, int off, int adjust,
387                                int x, int y, int w, int h) {
388
389         final float initConst = (dgdX*x) + gc;
390
391         // Limit step to fractional part of
392
// fastGradientArraySize (the non fractional part has
393
// no affect anyways, and would mess up lots of stuff
394
// below).
395
float step = (dgdX - (int)dgdX)*fastGradientArraySize;
396
397                 // Make it a Positive step (a small negative step is
398
// the same as a positive step slightly less than
399
// fastGradientArraySize.
400
if (step < 0)
401             step += fastGradientArraySize;
402
403         final int [] grad = gradient;
404
405         for(int i=0; i<h; i++) { //for every row
406
//initialize current value to be start.
407
float g = initConst + dgdY*(y+i);
408
409             // now Limited between -1 and 1.
410
g = g-(int)g;
411             // put in the positive side.
412
if (g < 0)
413                 g += 1;
414                         
415             // scale for gradient array...
416
g *= fastGradientArraySize;
417             g += 0.5; // rounding factor
418
final int rowLimit = off+w; // end of row iteration
419
while (off < rowLimit) {
420                 int idx = (int)g;
421                 if (idx >= fastGradientArraySize) {
422                     g -= fastGradientArraySize;
423                     idx -= fastGradientArraySize;
424                 }
425                 pixels[off++] = grad[idx];
426                 g += step;
427             }
428
429             off += adjust; //change in off from row to row
430
}
431     }
432
433
434     protected void fillSimpleReflect(int[] pixels, int off, int adjust,
435                                 int x, int y, int w, int h) {
436         final float initConst = (dgdX*x) + gc;
437
438         final int [] grad = gradient;
439
440         for (int i=0; i<h; i++) { //for every row
441
//initialize current value to be start.
442
float g = initConst + dgdY*(y+i);
443
444             // now limited g to -2<->2
445
g = g - 2*((int)(g/2.0f));
446
447             float step = dgdX;
448             // Pull it into the positive half
449
if (g < 0) {
450                 g = -g; //take absolute value
451
step = - step; // Change direction..
452
}
453
454             // Now do the same for dgdX. This is safe because
455
// any step that is a multiple of 2.0 has no
456
// affect, hence we can remove it which the first
457
// part does. The second part simply adds 2.0
458
// (which has no affect due to the cylcle) to move
459
// all negative step values into the positive
460
// side.
461
step = step - 2*((int)step/2.0f);
462             if (step < 0)
463                 step += 2.0;
464             final int reflectMax = 2*fastGradientArraySize;
465
466             // Scale for gradient array.
467
g *= fastGradientArraySize;
468             g += 0.5;
469             step *= fastGradientArraySize;
470             final int rowLimit = off+w; // end of row iteration
471
while (off < rowLimit) {
472                 int idx = (int)g;
473                 if (idx >= reflectMax) {
474                     g -= reflectMax;
475                     idx -= reflectMax;
476                 }
477
478                 if (idx <= fastGradientArraySize)
479                     pixels[off++] = grad[idx];
480                 else
481                     pixels[off++] = grad[reflectMax-idx];
482                 g+= step;
483             }
484
485             off += adjust; //change in off from row to row
486
}
487     }
488         
489     /**
490      * Return a Raster containing the colors generated for the graphics
491      * operation. This is where the area is filled with colors distributed
492      * linearly.
493      *
494      * @param x,y,w,h The area in device space for which colors are
495      * generated.
496      *
497      */

498     protected void fillRaster(int[] pixels, int off, int adjust,
499                               int x, int y, int w, int h) {
500     
501         //constant which can be pulled out of the inner loop
502
final float initConst = (dgdX*x) + gc;
503
504         if (fillMethod == ANTI_ALIAS_IMPL) {
505             //initialize current value to be start.
506
for(int i=0; i<h; i++){ //for every row
507
float g = initConst + dgdY*(y+i);
508                 
509                 final int rowLimit = off+w; // end of row iteration
510
while(off < rowLimit){ //for every pixel in this row.
511
//get the color
512
pixels[off++] = indexGradientAntiAlias(g, pixSz);
513                     g += dgdX; //incremental change in g
514
}
515                 off += adjust; //change in off from row to row
516
}
517         }
518         else if (!isSimpleLookup) {
519             if (cycleMethod == MultipleGradientPaint.NO_CYCLE) {
520                 fillHardNoCycle(pixels, off, adjust, x, y, w, h);
521             }
522             else {
523                 //initialize current value to be start.
524
for(int i=0; i<h; i++){ //for every row
525
float g = initConst + dgdY*(y+i);
526                 
527                     final int rowLimit = off+w; // end of row iteration
528
while(off < rowLimit){ //for every pixel in this row.
529
//get the color
530
pixels[off++] = indexIntoGradientsArrays(g);
531                         g += dgdX; //incremental change in g
532
}
533                     off += adjust; //change in off from row to row
534
}
535             }
536         } else {
537             // Simple implementations: just scale index by array size
538

539             if (cycleMethod == MultipleGradientPaint.NO_CYCLE)
540                 fillSimpleNoCycle(pixels, off, adjust, x, y, w, h);
541             else if (cycleMethod == MultipleGradientPaint.REPEAT)
542                 fillSimpleRepeat(pixels, off, adjust, x, y, w, h);
543             else //cycleMethod == MultipleGradientPaint.REFLECT
544
fillSimpleReflect(pixels, off, adjust, x, y, w, h);
545         }
546     }
547     
548     
549 }
550
Popular Tags