| 1 18 package org.apache.batik.ext.awt; 19 20 import java.awt.Color ; 21 import java.awt.PaintContext ; 22 import java.awt.Rectangle ; 23 import java.awt.RenderingHints ; 24 import java.awt.color.ColorSpace ; 25 import java.awt.geom.AffineTransform ; 26 import java.awt.geom.NoninvertibleTransformException ; 27 import java.awt.geom.Rectangle2D ; 28 import java.awt.image.ColorModel ; 29 import java.awt.image.DataBuffer ; 30 import java.awt.image.DataBufferInt ; 31 import java.awt.image.DirectColorModel ; 32 import java.awt.image.Raster ; 33 import java.awt.image.SinglePixelPackedSampleModel ; 34 import java.awt.image.WritableRaster ; 35 import java.lang.ref.WeakReference ; 36 37 import org.apache.batik.ext.awt.image.GraphicsUtil; 38 39 49 abstract class MultipleGradientPaintContext implements PaintContext { 50 51 protected final static boolean DEBUG = false; 52 53 56 protected ColorModel dataModel; 57 62 protected ColorModel model; 63 64 65 private static ColorModel lrgbmodel_NA = new DirectColorModel  66 (ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB), 67 24, 0xff0000, 0xFF00, 0xFF, 0x0, 68 false, DataBuffer.TYPE_INT); 69 70 private static ColorModel srgbmodel_NA = new DirectColorModel  71 (ColorSpace.getInstance(ColorSpace.CS_sRGB), 72 24, 0xff0000, 0xFF00, 0xFF, 0x0, 73 false, DataBuffer.TYPE_INT); 74 75 76 private static ColorModel lrgbmodel_A = new DirectColorModel  77 (ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB), 78 32, 0xff0000, 0xFF00, 0xFF, 0xFF000000, 79 false, DataBuffer.TYPE_INT); 80 81 private static ColorModel srgbmodel_A = new DirectColorModel  82 (ColorSpace.getInstance(ColorSpace.CS_sRGB), 83 32, 0xff0000, 0xFF00, 0xFF, 0xFF000000, 84 false, DataBuffer.TYPE_INT); 85 86 87 protected static ColorModel cachedModel; 88 89 90 protected static WeakReference cached; 91 92 93 protected WritableRaster saved; 94 95 96 protected MultipleGradientPaint.CycleMethodEnum cycleMethod; 97 98 99 protected MultipleGradientPaint.ColorSpaceEnum colorSpace; 100 101 102 protected float a00, a01, a10, a11, a02, a12; 103 104 110 protected boolean isSimpleLookup = true; 111 112 116 protected boolean hasDiscontinuity = false; 117 118 120 protected int fastGradientArraySize; 121 122 127 protected int[] gradient; 128 129 132 protected int[][] gradients; 133 134 138 protected int gradientAverage; 139 140 142 protected int gradientUnderflow; 143 144 146 protected int gradientOverflow; 147 148 149 protected int gradientsLength; 150 151 152 protected float[] normalizedIntervals; 153 154 155 protected float[] fractions; 156 157 158 private int transparencyTest; 159 160 161 private static final int SRGBtoLinearRGB[] = new int[256]; 162 private static final int LinearRGBtoSRGB[] = new int[256]; 163 164 static{ 166 for (int k = 0; k < 256; k++) { 167 SRGBtoLinearRGB[k] = convertSRGBtoLinearRGB(k); 168 LinearRGBtoSRGB[k] = convertLinearRGBtoSRGB(k); 169 } 170 } 171 172 175 protected static final int GRADIENT_SIZE = 256; 176 protected static final int GRADIENT_SIZE_INDEX = GRADIENT_SIZE -1; 177 178 183 private static final int MAX_GRADIENT_ARRAY_SIZE = 5000; 184 185 191 public MultipleGradientPaintContext(ColorModel cm, 192 Rectangle deviceBounds, 193 Rectangle2D userBounds, 194 AffineTransform t, 195 RenderingHints hints, 196 float[] fractions, 197 Color [] colors, 198 MultipleGradientPaint.CycleMethodEnum 199 cycleMethod, 200 MultipleGradientPaint.ColorSpaceEnum 201 colorSpace) 202 throws NoninvertibleTransformException  203 { 204 209 boolean fixFirst = false; 210 boolean fixLast = false; 211 int len = fractions.length; 212 213 if (fractions[0] != 0f) { 215 fixFirst = true; 216 len++; 217 } 218 219 if (fractions[fractions.length - 1] != 1f) { 221 fixLast = true; 222 len++; 223 } 224 225 for (int i=0; i<fractions.length-1; i++) 226 if (fractions[i] == fractions[i+1]) 227 len--; 228 229 this.fractions = new float[len]; 230 Color [] loColors = new Color [len-1]; 231 Color [] hiColors = new Color [len-1]; 232 normalizedIntervals = new float[len-1]; 233 234 gradientUnderflow = colors[0].getRGB(); 235 gradientOverflow = colors[colors.length-1].getRGB(); 236 237 int idx = 0; 238 if (fixFirst) { 239 this.fractions[0] = 0; 240 loColors[0] = colors[0]; 241 hiColors[0] = colors[0]; 242 normalizedIntervals[0] = fractions[0]; 243 idx++; 244 } 245 246 for (int i=0; i<fractions.length-1; i++) { 247 if (fractions[i] == fractions[i+1]) { 248 if (!colors[i].equals(colors[i+1])) { 250 hasDiscontinuity = true; 251 } 252 continue; 253 } 254 this.fractions[idx] = fractions[i]; 255 loColors[idx] = colors[i]; 256 hiColors[idx] = colors[i+1]; 257 normalizedIntervals[idx] = fractions[i+1]-fractions[i]; 258 idx++; 259 } 260 261 this.fractions[idx] = fractions[fractions.length-1]; 262 263 if (fixLast) { 264 loColors[idx] = hiColors[idx] = colors[colors.length-1]; 265 normalizedIntervals[idx] = 1-fractions[fractions.length-1]; 266 idx++; 267 this.fractions[idx] = 1; 268 } 269 270 AffineTransform tInv = t.createInverse(); 273 274 double m[] = new double[6]; 275 tInv.getMatrix(m); 276 a00 = (float)m[0]; 277 a10 = (float)m[1]; 278 a01 = (float)m[2]; 279 a11 = (float)m[3]; 280 a02 = (float)m[4]; 281 a12 = (float)m[5]; 282 283 this.cycleMethod = cycleMethod; 285 this.colorSpace = colorSpace; 286 287 if (cm.getColorSpace() == lrgbmodel_A.getColorSpace()) 289 dataModel = lrgbmodel_A; 290 else if (cm.getColorSpace() == srgbmodel_A.getColorSpace()) 291 dataModel = srgbmodel_A; 292 else 293 throw new IllegalArgumentException  294 ("Unsupported ColorSpace for interpolation"); 295 296 calculateGradientFractions(loColors, hiColors); 297 298 model = GraphicsUtil.coerceColorModel(dataModel, 299 cm.isAlphaPremultiplied()); 300 } 301 302 303 307 protected final void calculateGradientFractions 308 (Color []loColors, Color []hiColors) { 309 310 if (colorSpace == LinearGradientPaint.LINEAR_RGB) { 313 for (int i = 0; i < loColors.length; i++) { 314 loColors[i] = 315 new Color (SRGBtoLinearRGB[loColors[i].getRed()], 316 SRGBtoLinearRGB[loColors[i].getGreen()], 317 SRGBtoLinearRGB[loColors[i].getBlue()], 318 loColors[i].getAlpha()); 319 320 hiColors[i] = 321 new Color (SRGBtoLinearRGB[hiColors[i].getRed()], 322 SRGBtoLinearRGB[hiColors[i].getGreen()], 323 SRGBtoLinearRGB[hiColors[i].getBlue()], 324 hiColors[i].getAlpha()); 325 } 326 } 327 328 transparencyTest = 0xff000000; 330 if (cycleMethod == MultipleGradientPaint.NO_CYCLE) { 331 transparencyTest &= gradientUnderflow; 334 transparencyTest &= gradientOverflow; 335 } 336 337 gradients = new int[fractions.length - 1][]; 339 gradientsLength = gradients.length; 340 341 int n = normalizedIntervals.length; 343 344 float Imin = 1; 345 346 for(int i = 0; i < n; i++) { 347 Imin = (Imin > normalizedIntervals[i]) ? 348 normalizedIntervals[i] : Imin; 349 } 350 351 int estimatedSize = 0; 357 358 if (Imin == 0) { 359 estimatedSize = Integer.MAX_VALUE; 360 hasDiscontinuity = true; 361 } else { 362 for (int i = 0; i < normalizedIntervals.length; i++) { 363 estimatedSize += (normalizedIntervals[i]/Imin) * GRADIENT_SIZE; 364 } 365 } 366 367 368 if (estimatedSize > MAX_GRADIENT_ARRAY_SIZE) { 369 calculateMultipleArrayGradient(loColors, hiColors); 371 if ((cycleMethod == MultipleGradientPaint.REPEAT) && 372 (gradients[0][0] != 373 gradients[gradients.length-1][GRADIENT_SIZE_INDEX])) 374 hasDiscontinuity = true; 375 } else { 376 calculateSingleArrayGradient(loColors, hiColors, Imin); 378 if ((cycleMethod == MultipleGradientPaint.REPEAT) && 379 (gradient[0] != gradient[fastGradientArraySize])) 380 hasDiscontinuity = true; 381 } 382 383 if((transparencyTest >>> 24) == 0xff) { 385 if (dataModel.getColorSpace() == lrgbmodel_NA.getColorSpace()) 386 dataModel = lrgbmodel_NA; 387 else if (dataModel.getColorSpace() == srgbmodel_NA.getColorSpace()) 388 dataModel = srgbmodel_NA; 389 model = dataModel; 390 } 391 } 392 393 394 418 private void calculateSingleArrayGradient 419 (Color [] loColors, Color [] hiColors, float Imin) { 420 421 isSimpleLookup = true; 423 424 int rgb1; int rgb2; 426 427 int gradientsTot = 1; 429 int aveA = 0x008000; 431 int aveR = 0x008000; 432 int aveG = 0x008000; 433 int aveB = 0x008000; 434 435 for(int i=0; i < gradients.length; i++){ 437 438 int nGradients = (int)((normalizedIntervals[i]/Imin)*255f); 441 gradientsTot += nGradients; 442 gradients[i] = new int[nGradients]; 443 444 rgb1 = loColors[i].getRGB(); 446 rgb2 = hiColors[i].getRGB(); 447 448 interpolate(rgb1, rgb2, gradients[i]); 450 451 int argb = gradients[i][GRADIENT_SIZE/2]; 453 float norm = normalizedIntervals[i]; 454 aveA += (int)(((argb>> 8)&0xFF0000)*norm); 455 aveR += (int)(((argb )&0xFF0000)*norm); 456 aveG += (int)(((argb<< 8)&0xFF0000)*norm); 457 aveB += (int)(((argb<<16)&0xFF0000)*norm); 458 459 transparencyTest &= rgb1; 461 transparencyTest &= rgb2; 462 } 463 464 gradientAverage = (((aveA & 0xFF0000)<< 8) | 465 ((aveR & 0xFF0000) ) | 466 ((aveG & 0xFF0000)>> 8) | 467 ((aveB & 0xFF0000)>>16)); 468 469 gradient = new int[gradientsTot]; 471 int curOffset = 0; 472 for(int i = 0; i < gradients.length; i++){ 473 System.arraycopy(gradients[i], 0, gradient, 474 curOffset, gradients[i].length); 475 curOffset += gradients[i].length; 476 } 477 gradient[gradient.length-1] = hiColors[hiColors.length-1].getRGB(); 478 479 if (colorSpace == LinearGradientPaint.LINEAR_RGB) { 482 if (dataModel.getColorSpace() == 483 ColorSpace.getInstance(ColorSpace.CS_sRGB)) { 484 for (int i = 0; i < gradient.length; i++) { 485 gradient[i] = 486 convertEntireColorLinearRGBtoSRGB(gradient[i]); 487 } 488 gradientAverage = 489 convertEntireColorLinearRGBtoSRGB(gradientAverage); 490 } 491 } else { 492 if (dataModel.getColorSpace() == 493 ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB)) { 494 for (int i = 0; i < gradient.length; i++) { 495 gradient[i] = 496 convertEntireColorSRGBtoLinearRGB(gradient[i]); 497 } 498 gradientAverage = 499 convertEntireColorSRGBtoLinearRGB(gradientAverage); 500 } 501 } 502 503 fastGradientArraySize = gradient.length - 1; 504 } 505 506 507 526 private void calculateMultipleArrayGradient 527 (Color [] loColors, Color [] hiColors) { 528 529 isSimpleLookup = false; 531 532 int rgb1; int rgb2; 534 535 int aveA = 0x008000; 537 int aveR = 0x008000; 538 int aveG = 0x008000; 539 int aveB = 0x008000; 540 541 for(int i=0; i < gradients.length; i++){ 543 544 if (normalizedIntervals[i] == 0) 546 continue; 547 548 gradients[i] = new int[GRADIENT_SIZE]; 550 551 rgb1 = loColors[i].getRGB(); 553 rgb2 = hiColors[i].getRGB(); 554 555 interpolate(rgb1, rgb2, gradients[i]); 557 558 int argb = gradients[i][GRADIENT_SIZE/2]; 560 float norm = normalizedIntervals[i]; 561 aveA += (int)(((argb>> 8)&0xFF0000)*norm); 562 aveR += (int)(((argb )&0xFF0000)*norm); 563 aveG += (int)(((argb<< 8)&0xFF0000)*norm); 564 aveB += (int)(((argb<<16)&0xFF0000)*norm); 565 566 transparencyTest &= rgb1; 568 transparencyTest &= rgb2; 569 } 570 571 gradientAverage = (((aveA & 0xFF0000)<< 8) | 572 ((aveR & 0xFF0000) ) | 573 ((aveG & 0xFF0000)>> 8) | 574 ((aveB & 0xFF0000)>>16)); 575 576 if (colorSpace == LinearGradientPaint.LINEAR_RGB) { 579 if (dataModel.getColorSpace() == 580 ColorSpace.getInstance(ColorSpace.CS_sRGB)) { 581 for (int j = 0; j < gradients.length; j++) { 582 for (int i = 0; i < gradients[j].length; i++) { 583 gradients[j][i] = 584 convertEntireColorLinearRGBtoSRGB(gradients[j][i]); 585 } 586 } 587 gradientAverage = 588 convertEntireColorLinearRGBtoSRGB(gradientAverage); 589 } 590 } else { 591 if (dataModel.getColorSpace() == 592 ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB)) { 593 for (int j = 0; j < gradients.length; j++) { 594 for (int i = 0; i < gradients[j].length; i++) { 595 gradients[j][i] = 596 convertEntireColorSRGBtoLinearRGB(gradients[j][i]); 597 } 598 } 599 gradientAverage = 600 convertEntireColorSRGBtoLinearRGB(gradientAverage); 601 } 602 } 603 } 604 605 613 private void interpolate(int rgb1, int rgb2, int[] output) { 614 615 int a1, r1, g1, b1, da, dr, dg, db; 617 float stepSize = 1/(float)output.length; 619 620 a1 = (rgb1 >> 24) & 0xff; 622 r1 = (rgb1 >> 16) & 0xff; 623 g1 = (rgb1 >> 8) & 0xff; 624 b1 = (rgb1 ) & 0xff; 625 da = ((rgb2 >> 24) & 0xff) - a1; 627 dr = ((rgb2 >> 16) & 0xff) - r1; 628 dg = ((rgb2 >> 8) & 0xff) - g1; 629 db = ((rgb2 ) & 0xff) - b1; 630 631 for (int i = 0; i < output.length; i++) { 635 output[i] = 636 (((int) ((a1 + i * da * stepSize) + .5) << 24)) | 637 (((int) ((r1 + i * dr * stepSize) + .5) << 16)) | 638 (((int) ((g1 + i * dg * stepSize) + .5) << 8)) | 639 (((int) ((b1 + i * db * stepSize) + .5) )); 640 } 641 } 642 643 644 648 private int convertEntireColorLinearRGBtoSRGB(int rgb) { 649 650 int a1, r1, g1, b1; 652 a1 = (rgb >> 24) & 0xff; 654 r1 = (rgb >> 16) & 0xff; 655 g1 = (rgb >> 8) & 0xff; 656 b1 = rgb & 0xff; 657 658 r1 = LinearRGBtoSRGB[r1]; 660 g1 = LinearRGBtoSRGB[g1]; 661 b1 = LinearRGBtoSRGB[b1]; 662 663 return ((a1 << 24) | 665 (r1 << 16) | 666 (g1 << 8) | 667 b1); 668 } 669 670 674 private int convertEntireColorSRGBtoLinearRGB(int rgb) { 675 676 int a1, r1, g1, b1; 678 a1 = (rgb >> 24) & 0xff; 680 r1 = (rgb >> 16) & 0xff; 681 g1 = (rgb >> 8) & 0xff; 682 b1 = rgb & 0xff; 683 684 r1 = SRGBtoLinearRGB[r1]; 686 g1 = SRGBtoLinearRGB[g1]; 687 b1 = SRGBtoLinearRGB[b1]; 688 689 return ((a1 << 24) | 691 (r1 << 16) | 692 (g1 << 8) | 693 b1); 694 } 695 696 697 708 protected final int indexIntoGradientsArrays(float position) { 709 710 712 if (cycleMethod == MultipleGradientPaint.NO_CYCLE) { 713 714 if (position >= 1) { return gradientOverflow; 716 } 717 718 else if (position <= 0) { return gradientUnderflow; 720 } 721 } 722 723 else if (cycleMethod == MultipleGradientPaint.REPEAT) { 724 position = position - (int)position; 727 728 730 if (position < 0) { 731 position = position + 1; } 733 734 int w=0, c1=0, c2=0; 735 if (isSimpleLookup) { 736 position *= gradient.length; 737 int idx1 = (int)(position); 738 if (idx1+1 < gradient.length) 739 return gradient[idx1]; 740 741 w = (int)((position-idx1)*(1<<16)); 742 c1 = gradient[idx1]; 743 c2 = gradient[0]; 744 } else { 745 for (int i = 0; i < gradientsLength; i++) { 747 748 if (position < fractions[i+1]) { 750 float delta = position - fractions[i]; 751 752 delta = ((delta / normalizedIntervals[i]) * GRADIENT_SIZE); 753 int index = (int)delta; 755 if ((index+1<gradients[i].length) || 756 (i+1 < gradientsLength)) 757 return gradients[i][index]; 758 759 w = (int)((delta-index)*(1<<16)); 760 c1 = gradients[i][index]; 761 c2 = gradients[0][0]; 762 break; 763 } 764 } 765 } 766 767 return 768 (((( ( (c1>> 8) &0xFF0000)+ 769 ((((c2>>>24) )-((c1>>>24) ))*w))&0xFF0000)<< 8) | 770 771 ((( ( (c1 ) &0xFF0000)+ 772 ((((c2>> 16)&0xFF)-((c1>> 16)&0xFF))*w))&0xFF0000) ) | 773 774 ((( ( (c1<< 8) &0xFF0000)+ 775 ((((c2>> 8)&0xFF)-((c1>> 8)&0xFF))*w))&0xFF0000)>> 8) | 776 777 ((( ( (c1<< 16) &0xFF0000)+ 778 ((((c2 )&0xFF)-((c1 )&0xFF))*w))&0xFF0000)>>16)); 779 780 } 786 787 else { 789 if (position < 0) { 790 position = -position; } 792 793 int part = (int)position; 795 position = position - part; 797 if ((part & 0x00000001) == 1) { position = 1 - position; } 800 } 801 802 804 if (isSimpleLookup) { return gradient[(int)(position * fastGradientArraySize)]; 806 } 807 808 else { 810 for (int i = 0; i < gradientsLength; i++) { 812 813 if (position < fractions[i+1]) { 815 &n
|