1 7 8 package java.awt; 9 10 import java.awt.MultipleGradientPaint.CycleMethod ; 11 import java.awt.MultipleGradientPaint.ColorSpaceType ; 12 import java.awt.color.ColorSpace ; 13 import java.awt.geom.AffineTransform ; 14 import java.awt.geom.NoninvertibleTransformException ; 15 import java.awt.geom.Rectangle2D ; 16 import java.awt.image.ColorModel ; 17 import java.awt.image.DataBuffer ; 18 import java.awt.image.DataBufferInt ; 19 import java.awt.image.DirectColorModel ; 20 import java.awt.image.Raster ; 21 import java.awt.image.SinglePixelPackedSampleModel ; 22 import java.awt.image.WritableRaster ; 23 import java.lang.ref.SoftReference ; 24 import java.lang.ref.WeakReference ; 25 import java.util.Arrays ; 26 27 35 abstract class MultipleGradientPaintContext implements PaintContext { 36 37 41 protected ColorModel model; 42 43 44 private static ColorModel xrgbmodel = 45 new DirectColorModel (24, 0x00ff0000, 0x0000ff00, 0x000000ff); 46 47 48 protected static ColorModel cachedModel; 49 50 51 protected static WeakReference <Raster > cached; 52 53 54 protected Raster saved; 55 56 57 protected CycleMethod cycleMethod; 58 59 60 protected ColorSpaceType colorSpace; 61 62 63 protected float a00, a01, a10, a11, a02, a12; 64 65 72 protected boolean isSimpleLookup; 73 74 78 protected int fastGradientArraySize; 79 80 85 protected int[] gradient; 86 87 91 private int[][] gradients; 92 93 94 private float[] normalizedIntervals; 95 96 97 private float[] fractions; 98 99 100 private int transparencyTest; 101 102 103 private static final int SRGBtoLinearRGB[] = new int[256]; 104 private static final int LinearRGBtoSRGB[] = new int[256]; 105 106 static { 107 for (int k = 0; k < 256; k++) { 109 SRGBtoLinearRGB[k] = convertSRGBtoLinearRGB(k); 110 LinearRGBtoSRGB[k] = convertLinearRGBtoSRGB(k); 111 } 112 } 113 114 118 protected static final int GRADIENT_SIZE = 256; 119 protected static final int GRADIENT_SIZE_INDEX = GRADIENT_SIZE -1; 120 121 127 private static final int MAX_GRADIENT_ARRAY_SIZE = 5000; 128 129 132 protected MultipleGradientPaintContext(MultipleGradientPaint mgp, 133 ColorModel cm, 134 Rectangle deviceBounds, 135 Rectangle2D userBounds, 136 AffineTransform t, 137 RenderingHints hints, 138 float[] fractions, 139 Color [] colors, 140 CycleMethod cycleMethod, 141 ColorSpaceType colorSpace) 142 { 143 if (deviceBounds == null) { 144 throw new NullPointerException ("Device bounds cannot be null"); 145 } 146 147 if (userBounds == null) { 148 throw new NullPointerException ("User bounds cannot be null"); 149 } 150 151 if (t == null) { 152 throw new NullPointerException ("Transform cannot be null"); 153 } 154 155 if (hints == null) { 156 throw new NullPointerException ("RenderingHints cannot be null"); 157 } 158 159 AffineTransform tInv; 162 try { 163 t.invert(); 166 tInv = t; 167 } catch (NoninvertibleTransformException e) { 168 tInv = new AffineTransform (); 171 } 172 double m[] = new double[6]; 173 tInv.getMatrix(m); 174 a00 = (float)m[0]; 175 a10 = (float)m[1]; 176 a01 = (float)m[2]; 177 a11 = (float)m[3]; 178 a02 = (float)m[4]; 179 a12 = (float)m[5]; 180 181 this.cycleMethod = cycleMethod; 183 this.colorSpace = colorSpace; 184 185 this.fractions = fractions; 187 188 int[] gradient = 192 (mgp.gradient != null) ? mgp.gradient.get() : null; 193 int[][] gradients = 194 (mgp.gradients != null) ? mgp.gradients.get() : null; 195 196 if (gradient == null && gradients == null) { 197 calculateLookupData(colors); 199 200 mgp.model = this.model; 203 mgp.normalizedIntervals = this.normalizedIntervals; 204 mgp.isSimpleLookup = this.isSimpleLookup; 205 if (isSimpleLookup) { 206 mgp.fastGradientArraySize = this.fastGradientArraySize; 208 mgp.gradient = new SoftReference <int[]>(this.gradient); 209 } else { 210 mgp.gradients = new SoftReference <int[][]>(this.gradients); 212 } 213 } else { 214 this.model = mgp.model; 216 this.normalizedIntervals = mgp.normalizedIntervals; 217 this.isSimpleLookup = mgp.isSimpleLookup; 218 this.gradient = gradient; 219 this.fastGradientArraySize = mgp.fastGradientArraySize; 220 this.gradients = gradients; 221 } 222 } 223 224 229 private void calculateLookupData(Color [] colors) { 230 Color [] normalizedColors; 231 if (colorSpace == ColorSpaceType.LINEAR_RGB) { 232 normalizedColors = new Color [colors.length]; 234 for (int i = 0; i < colors.length; i++) { 236 int argb = colors[i].getRGB(); 237 int a = argb >>> 24; 238 int r = SRGBtoLinearRGB[(argb >> 16) & 0xff]; 239 int g = SRGBtoLinearRGB[(argb >> 8) & 0xff]; 240 int b = SRGBtoLinearRGB[(argb ) & 0xff]; 241 normalizedColors[i] = new Color (r, g, b, a); 242 } 243 } else { 244 normalizedColors = colors; 247 } 248 249 normalizedIntervals = new float[fractions.length-1]; 251 252 for (int i = 0; i < normalizedIntervals.length; i++) { 254 normalizedIntervals[i] = this.fractions[i+1] - this.fractions[i]; 256 } 257 258 transparencyTest = 0xff000000; 260 261 gradients = new int[normalizedIntervals.length][]; 263 264 float Imin = 1; 266 for (int i = 0; i < normalizedIntervals.length; i++) { 267 Imin = (Imin > normalizedIntervals[i]) ? 268 normalizedIntervals[i] : Imin; 269 } 270 271 int estimatedSize = 0; 277 for (int i = 0; i < normalizedIntervals.length; i++) { 278 estimatedSize += (normalizedIntervals[i]/Imin) * GRADIENT_SIZE; 279 } 280 281 if (estimatedSize > MAX_GRADIENT_ARRAY_SIZE) { 282 calculateMultipleArrayGradient(normalizedColors); 284 } else { 285 calculateSingleArrayGradient(normalizedColors, Imin); 287 } 288 289 if ((transparencyTest >>> 24) == 0xff) { 291 model = xrgbmodel; 292 } else { 293 model = ColorModel.getRGBdefault(); 294 } 295 } 296 297 320 private void calculateSingleArrayGradient(Color [] colors, float Imin) { 321 isSimpleLookup = true; 323 324 int rgb1, rgb2; 326 327 int gradientsTot = 1; 329 330 for (int i = 0; i < gradients.length; i++) { 332 int nGradients = (int)((normalizedIntervals[i]/Imin)*255f); 335 gradientsTot += nGradients; 336 gradients[i] = new int[nGradients]; 337 338 rgb1 = colors[i].getRGB(); 340 rgb2 = colors[i+1].getRGB(); 341 342 interpolate(rgb1, rgb2, gradients[i]); 344 345 transparencyTest &= rgb1; 348 transparencyTest &= rgb2; 349 } 350 351 gradient = new int[gradientsTot]; 353 int curOffset = 0; 354 for (int i = 0; i < gradients.length; i++){ 355 System.arraycopy(gradients[i], 0, gradient, 356 curOffset, gradients[i].length); 357 curOffset += gradients[i].length; 358 } 359 gradient[gradient.length-1] = colors[colors.length-1].getRGB(); 360 361 if (colorSpace == ColorSpaceType.LINEAR_RGB) { 364 for (int i = 0; i < gradient.length; i++) { 365 gradient[i] = convertEntireColorLinearRGBtoSRGB(gradient[i]); 366 } 367 } 368 369 fastGradientArraySize = gradient.length - 1; 370 } 371 372 390 private void calculateMultipleArrayGradient(Color [] colors) { 391 isSimpleLookup = false; 393 394 int rgb1, rgb2; 396 397 for (int i = 0; i < gradients.length; i++){ 399 gradients[i] = new int[GRADIENT_SIZE]; 402 403 rgb1 = colors[i].getRGB(); 405 rgb2 = colors[i+1].getRGB(); 406 407 interpolate(rgb1, rgb2, gradients[i]); 409 410 transparencyTest &= rgb1; 413 transparencyTest &= rgb2; 414 } 415 416 if (colorSpace == ColorSpaceType.LINEAR_RGB) { 419 for (int j = 0; j < gradients.length; j++) { 420 for (int i = 0; i < gradients[j].length; i++) { 421 gradients[j][i] = 422 convertEntireColorLinearRGBtoSRGB(gradients[j][i]); 423 } 424 } 425 } 426 } 427 428 436 private void interpolate(int rgb1, int rgb2, int[] output) { 437 int a1, r1, g1, b1, da, dr, dg, db; 439 440 float stepSize = 1.0f / output.length; 442 443 a1 = (rgb1 >> 24) & 0xff; 445 r1 = (rgb1 >> 16) & 0xff; 446 g1 = (rgb1 >> 8) & 0xff; 447 b1 = (rgb1 ) & 0xff; 448 449 da = ((rgb2 >> 24) & 0xff) - a1; 451 dr = ((rgb2 >> 16) & 0xff) - r1; 452 dg = ((rgb2 >> 8) & 0xff) - g1; 453 db = ((rgb2 ) & 0xff) - b1; 454 455 for (int i = 0; i < output.length; i++) { 459 output[i] = 460 (((int) ((a1 + i * da * stepSize) + 0.5) << 24)) | 461 (((int) ((r1 + i * dr * stepSize) + 0.5) << 16)) | 462 (((int) ((g1 + i * dg * stepSize) + 0.5) << 8)) | 463 (((int) ((b1 + i * db * stepSize) + 0.5) )); 464 } 465 } 466 467 472 private int convertEntireColorLinearRGBtoSRGB(int rgb) { 473 int a1, r1, g1, b1; 475 476 a1 = (rgb >> 24) & 0xff; 478 r1 = (rgb >> 16) & 0xff; 479 g1 = (rgb >> 8) & 0xff; 480 b1 = (rgb ) & 0xff; 481 482 r1 = LinearRGBtoSRGB[r1]; 484 g1 = LinearRGBtoSRGB[g1]; 485 b1 = LinearRGBtoSRGB[b1]; 486 487 return ((a1 << 24) | 489 (r1 << 16) | 490 (g1 << 8) | 491 (b1 )); 492 } 493 494 504 protected final int indexIntoGradientsArrays(float position) { 505 if (cycleMethod == CycleMethod.NO_CYCLE) { 507 if (position > 1) { 508 position = 1; 510 } else if (position < 0) { 511 position = 0; 513 } 514 } else if (cycleMethod == CycleMethod.REPEAT) { 515 position = position - (int)position; 518 519 if (position < 0) { 521 position = position + 1; 523 } 524 } else { if (position < 0) { 526 position = -position; 528 } 529 530 int part = (int)position; 532 533 position = position - part; 535 536 if ((part & 1) == 1) { 537 position = 1 - position; 539 } 540 } 541 542 544 if (isSimpleLookup) { 545 return gradient[(int)(position * fastGradientArraySize)]; 547 } else { 548 550 for (int i = 0; i < gradients.length; i++) { 552 if (position < fractions[i+1]) { 553 float delta = position - fractions[i]; 555 556 int index = (int)((delta / normalizedIntervals[i]) 558 * (GRADIENT_SIZE_INDEX)); 559 560 return gradients[i][index]; 561 } 562 } 563 } 564 565 return gradients[gradients.length - 1][GRADIENT_SIZE_INDEX]; 566 } 567 568 572 private static int convertSRGBtoLinearRGB(int color) { 573 float input, output; 574 575 input = color / 255.0f; 576 if (input <= 0.04045f) { 577 output = input / 12.92f; 578 } else { 579 output = (float)Math.pow((input + 0.055) / 1.055, 2.4); 580 } 581 582 return Math.round(output * 255.0f); 583 } 584 585 589 private static int convertLinearRGBtoSRGB(int color) { 590 float input, output; 591 592 input = color/255.0f; 593 if (input <= 0.0031308) { 594 output = input * 12.92f; 595 } else { 596 output = (1.055f * 597 ((float) Math.pow(input, (1.0 / 2.4)))) - 0.055f; 598 } 599 600 return Math.round(output * 255.0f); 601 } 602 603 606 public final Raster getRaster(int x, int y, int w, int h) { 607 Raster raster = saved; 610 if (raster == null || 611 raster.getWidth() < w || raster.getHeight() < h) 612 { 613 raster = getCachedRaster(model, w, h); 614 saved = raster; 615 } 616 617 DataBufferInt rasterDB = (DataBufferInt )raster.getDataBuffer(); 623 int[] pixels = rasterDB.getBankData()[0]; 624 int off = rasterDB.getOffset(); 625 int scanlineStride = ((SinglePixelPackedSampleModel ) 626 raster.getSampleModel()).getScanlineStride(); 627 int adjust = scanlineStride - w; 628 629 fillRaster(pixels, off, adjust, x, y, w, h); 631 return raster; 632 } 633 634 protected abstract void fillRaster(int pixels[], int off, int adjust, 635 int x, int y, int w, int h); 636 637 638 643 private static synchronized Raster getCachedRaster(ColorModel cm, 644 int w, int h) 645 { 646 if (cm == cachedModel) { 647 if (cached != null) { 648 Raster ras = (Raster ) cached.get(); 649 if (ras != null && 650 ras.getWidth() >= w && 651 ras.getHeight() >= h) 652 { 653 cached = null; 654 return ras; 655 } 656 } 657 } 658 return cm.createCompatibleWritableRaster(w, h); 659 } 660 661 666 private static synchronized void putCachedRaster(ColorModel cm, 667 Raster ras) 668 { 669 if (cached != null) { 670 Raster cras = (Raster ) cached.get(); 671 if (cras != null) { 672 int cw = cras.getWidth(); 673 int ch = cras.getHeight(); 674 int iw = ras.getWidth(); 675 int ih = ras.getHeight(); 676 if (cw >= iw && ch >= ih) { 677 return; 678 } 679 if (cw * ch >= iw * ih) { 680 return; 681 } 682 } 683 } 684 cachedModel = cm; 685 cached = new WeakReference <Raster >(ras); 686 } 687 688 691 public final void dispose() { 692 if (saved != null) { 693 putCachedRaster(model, saved); 694 saved = null; 695 } 696 } 697 698 701 public final ColorModel getColorModel() { 702 return model; 703 } 704 } 705 | Popular Tags |