1 /* 2 * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package java.awt; 27 28 import java.awt.image.BufferedImage; 29 import java.awt.image.Raster; 30 import java.awt.image.WritableRaster; 31 import java.awt.image.ColorModel; 32 import java.awt.image.DirectColorModel; 33 import java.awt.image.IndexColorModel; 34 import java.awt.geom.AffineTransform; 35 import java.awt.geom.NoninvertibleTransformException; 36 import java.lang.ref.WeakReference; 37 import sun.awt.image.SunWritableRaster; 38 import sun.awt.image.IntegerInterleavedRaster; 39 import sun.awt.image.ByteInterleavedRaster; 40 41 abstract class TexturePaintContext implements PaintContext { 42 public static ColorModel xrgbmodel = 43 new DirectColorModel(24, 0xff0000, 0xff00, 0xff); 44 public static ColorModel argbmodel = ColorModel.getRGBdefault(); 45 46 ColorModel colorModel; 47 int bWidth; 48 int bHeight; 49 int maxWidth; 50 51 WritableRaster outRas; 52 53 double xOrg; 54 double yOrg; 55 double incXAcross; 56 double incYAcross; 57 double incXDown; 58 double incYDown; 59 60 int colincx; 61 int colincy; 62 int colincxerr; 63 int colincyerr; 64 int rowincx; 65 int rowincy; 66 int rowincxerr; 67 int rowincyerr; 68 69 public static PaintContext getContext(BufferedImage bufImg, 70 AffineTransform xform, 71 RenderingHints hints, 72 Rectangle devBounds) { 73 WritableRaster raster = bufImg.getRaster(); 74 ColorModel cm = bufImg.getColorModel(); 75 int maxw = devBounds.width; 76 Object val = hints.get(RenderingHints.KEY_INTERPOLATION); 77 boolean filter = 78 (val == null 79 ? (hints.get(RenderingHints.KEY_RENDERING) == RenderingHints.VALUE_RENDER_QUALITY) 80 : (val != RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)); 81 if (raster instanceof IntegerInterleavedRaster && 82 (!filter || isFilterableDCM(cm))) 83 { 84 IntegerInterleavedRaster iir = (IntegerInterleavedRaster) raster; 85 if (iir.getNumDataElements() == 1 && iir.getPixelStride() == 1) { 86 return new Int(iir, cm, xform, maxw, filter); 87 } 88 } else if (raster instanceof ByteInterleavedRaster) { 89 ByteInterleavedRaster bir = (ByteInterleavedRaster) raster; 90 if (bir.getNumDataElements() == 1 && bir.getPixelStride() == 1) { 91 if (filter) { 92 if (isFilterableICM(cm)) { 93 return new ByteFilter(bir, cm, xform, maxw); 94 } 95 } else { 96 return new Byte(bir, cm, xform, maxw); 97 } 98 } 99 } 100 return new Any(raster, cm, xform, maxw, filter); 101 } 102 103 public static boolean isFilterableICM(ColorModel cm) { 104 if (cm instanceof IndexColorModel) { 105 IndexColorModel icm = (IndexColorModel) cm; 106 if (icm.getMapSize() <= 256) { 107 return true; 108 } 109 } 110 return false; 111 } 112 113 public static boolean isFilterableDCM(ColorModel cm) { 114 if (cm instanceof DirectColorModel) { 115 DirectColorModel dcm = (DirectColorModel) cm; 116 return (isMaskOK(dcm.getAlphaMask(), true) && 117 isMaskOK(dcm.getRedMask(), false) && 118 isMaskOK(dcm.getGreenMask(), false) && 119 isMaskOK(dcm.getBlueMask(), false)); 120 } 121 return false; 122 } 123 124 public static boolean isMaskOK(int mask, boolean canbezero) { 125 if (canbezero && mask == 0) { 126 return true; 127 } 128 return (mask == 0xff || 129 mask == 0xff00 || 130 mask == 0xff0000 || 131 mask == 0xff000000); 132 } 133 134 public static ColorModel getInternedColorModel(ColorModel cm) { 135 if (xrgbmodel == cm || xrgbmodel.equals(cm)) { 136 return xrgbmodel; 137 } 138 if (argbmodel == cm || argbmodel.equals(cm)) { 139 return argbmodel; 140 } 141 return cm; 142 } 143 144 TexturePaintContext(ColorModel cm, AffineTransform xform, 145 int bWidth, int bHeight, int maxw) { 146 this.colorModel = getInternedColorModel(cm); 147 this.bWidth = bWidth; 148 this.bHeight = bHeight; 149 this.maxWidth = maxw; 150 151 try { 152 xform = xform.createInverse(); 153 } catch (NoninvertibleTransformException e) { 154 xform.setToScale(0, 0); 155 } 156 this.incXAcross = mod(xform.getScaleX(), bWidth); 157 this.incYAcross = mod(xform.getShearY(), bHeight); 158 this.incXDown = mod(xform.getShearX(), bWidth); 159 this.incYDown = mod(xform.getScaleY(), bHeight); 160 this.xOrg = xform.getTranslateX(); 161 this.yOrg = xform.getTranslateY(); 162 this.colincx = (int) incXAcross; 163 this.colincy = (int) incYAcross; 164 this.colincxerr = fractAsInt(incXAcross); 165 this.colincyerr = fractAsInt(incYAcross); 166 this.rowincx = (int) incXDown; 167 this.rowincy = (int) incYDown; 168 this.rowincxerr = fractAsInt(incXDown); 169 this.rowincyerr = fractAsInt(incYDown); 170 171 } 172 173 static int fractAsInt(double d) { 174 return (int) ((d % 1.0) * Integer.MAX_VALUE); 175 } 176 177 static double mod(double num, double den) { 178 num = num % den; 179 if (num < 0) { 180 num += den; 181 if (num >= den) { 182 // For very small negative numerators, the answer might 183 // be such a tiny bit less than den that the difference 184 // is smaller than the mantissa of a double allows and 185 // the result would then be rounded to den. If that is 186 // the case then we map that number to 0 as the nearest 187 // modulus representation. 188 num = 0; 189 } 190 } 191 return num; 192 } 193 194 /** 195 * Release the resources allocated for the operation. 196 */ 197 public void dispose() { 198 dropRaster(colorModel, outRas); 199 } 200 201 /** 202 * Return the ColorModel of the output. 203 */ 204 public ColorModel getColorModel() { 205 return colorModel; 206 } 207 208 /** 209 * Return a Raster containing the colors generated for the graphics 210 * operation. 211 * @param x,y,w,h The area in device space for which colors are 212 * generated. 213 */ 214 public Raster getRaster(int x, int y, int w, int h) { 215 if (outRas == null || 216 outRas.getWidth() < w || 217 outRas.getHeight() < h) 218 { 219 // If h==1, we will probably get lots of "scanline" rects 220 outRas = makeRaster((h == 1 ? Math.max(w, maxWidth) : w), h); 221 } 222 double X = mod(xOrg + x * incXAcross + y * incXDown, bWidth); 223 double Y = mod(yOrg + x * incYAcross + y * incYDown, bHeight); 224 225 setRaster((int) X, (int) Y, fractAsInt(X), fractAsInt(Y), 226 w, h, bWidth, bHeight, 227 colincx, colincxerr, 228 colincy, colincyerr, 229 rowincx, rowincxerr, 230 rowincy, rowincyerr); 231 232 SunWritableRaster.markDirty(outRas); 233 234 return outRas; 235 } 236 237 private static WeakReference<Raster> xrgbRasRef; 238 private static WeakReference<Raster> argbRasRef; 239 240 static synchronized WritableRaster makeRaster(ColorModel cm, 241 Raster srcRas, 242 int w, int h) 243 { 244 if (xrgbmodel == cm) { 245 if (xrgbRasRef != null) { 246 WritableRaster wr = (WritableRaster) xrgbRasRef.get(); 247 if (wr != null && wr.getWidth() >= w && wr.getHeight() >= h) { 248 xrgbRasRef = null; 249 return wr; 250 } 251 } 252 // If we are going to cache this Raster, make it non-tiny 253 if (w <= 32 && h <= 32) { 254 w = h = 32; 255 } 256 } else if (argbmodel == cm) { 257 if (argbRasRef != null) { 258 WritableRaster wr = (WritableRaster) argbRasRef.get(); 259 if (wr != null && wr.getWidth() >= w && wr.getHeight() >= h) { 260 argbRasRef = null; 261 return wr; 262 } 263 } 264 // If we are going to cache this Raster, make it non-tiny 265 if (w <= 32 && h <= 32) { 266 w = h = 32; 267 } 268 } 269 if (srcRas != null) { 270 return srcRas.createCompatibleWritableRaster(w, h); 271 } else { 272 return cm.createCompatibleWritableRaster(w, h); 273 } 274 } 275 276 static synchronized void dropRaster(ColorModel cm, Raster outRas) { 277 if (outRas == null) { 278 return; 279 } 280 if (xrgbmodel == cm) { 281 xrgbRasRef = new WeakReference<>(outRas); 282 } else if (argbmodel == cm) { 283 argbRasRef = new WeakReference<>(outRas); 284 } 285 } 286 287 private static WeakReference<Raster> byteRasRef; 288 289 static synchronized WritableRaster makeByteRaster(Raster srcRas, 290 int w, int h) 291 { 292 if (byteRasRef != null) { 293 WritableRaster wr = (WritableRaster) byteRasRef.get(); 294 if (wr != null && wr.getWidth() >= w && wr.getHeight() >= h) { 295 byteRasRef = null; 296 return wr; 297 } 298 } 299 // If we are going to cache this Raster, make it non-tiny 300 if (w <= 32 && h <= 32) { 301 w = h = 32; 302 } 303 return srcRas.createCompatibleWritableRaster(w, h); 304 } 305 306 static synchronized void dropByteRaster(Raster outRas) { 307 if (outRas == null) { 308 return; 309 } 310 byteRasRef = new WeakReference<>(outRas); 311 } 312 313 public abstract WritableRaster makeRaster(int w, int h); 314 public abstract void setRaster(int x, int y, int xerr, int yerr, 315 int w, int h, int bWidth, int bHeight, 316 int colincx, int colincxerr, 317 int colincy, int colincyerr, 318 int rowincx, int rowincxerr, 319 int rowincy, int rowincyerr); 320 321 /* 322 * Blends the four ARGB values in the rgbs array using the factors 323 * described by xmul and ymul in the following ratio: 324 * 325 * rgbs[0] * (1-xmul) * (1-ymul) + 326 * rgbs[1] * ( xmul) * (1-ymul) + 327 * rgbs[2] * (1-xmul) * ( ymul) + 328 * rgbs[3] * ( xmul) * ( ymul) 329 * 330 * xmul and ymul are integer values in the half-open range [0, 2^31) 331 * where 0 == 0.0 and 2^31 == 1.0. 332 * 333 * Note that since the range is half-open, the values are always 334 * logically less than 1.0. This makes sense because while choosing 335 * pixels to blend, when the error values reach 1.0 we move to the 336 * next pixel and reset them to 0.0. 337 */ 338 public static int blend(int[] rgbs, int xmul, int ymul) { 339 // xmul/ymul are 31 bits wide, (0 => 2^31-1) 340 // shift them to 12 bits wide, (0 => 2^12-1) 341 xmul = (xmul >>> 19); 342 ymul = (ymul >>> 19); 343 int accumA, accumR, accumG, accumB; 344 accumA = accumR = accumG = accumB = 0; 345 for (int i = 0; i < 4; i++) { 346 int rgb = rgbs[i]; 347 // The complement of the [xy]mul values (1-[xy]mul) can result 348 // in new values in the range (1 => 2^12). Thus for any given 349 // loop iteration, the values could be anywhere in (0 => 2^12). 350 xmul = (1<<12) - xmul; 351 if ((i & 1) == 0) { 352 ymul = (1<<12) - ymul; 353 } 354 // xmul and ymul are each 12 bits (0 => 2^12) 355 // factor is thus 24 bits (0 => 2^24) 356 int factor = xmul * ymul; 357 if (factor != 0) { 358 // accum variables will accumulate 32 bits 359 // bytes extracted from rgb fit in 8 bits (0 => 255) 360 // byte * factor thus fits in 32 bits (0 => 255 * 2^24) 361 accumA += (((rgb >>> 24) ) * factor); 362 accumR += (((rgb >>> 16) & 0xff) * factor); 363 accumG += (((rgb >>> 8) & 0xff) * factor); 364 accumB += (((rgb ) & 0xff) * factor); 365 } 366 } 367 return ((((accumA + (1<<23)) >>> 24) << 24) | 368 (((accumR + (1<<23)) >>> 24) << 16) | 369 (((accumG + (1<<23)) >>> 24) << 8) | 370 (((accumB + (1<<23)) >>> 24) )); 371 } 372 373 static class Int extends TexturePaintContext { 374 IntegerInterleavedRaster srcRas; 375 int[] inData; 376 int inOff; 377 int inSpan; 378 int[] outData; 379 int outOff; 380 int outSpan; 381 boolean filter; 382 383 public Int(IntegerInterleavedRaster srcRas, ColorModel cm, 384 AffineTransform xform, int maxw, boolean filter) 385 { 386 super(cm, xform, srcRas.getWidth(), srcRas.getHeight(), maxw); 387 this.srcRas = srcRas; 388 this.inData = srcRas.getDataStorage(); 389 this.inSpan = srcRas.getScanlineStride(); 390 this.inOff = srcRas.getDataOffset(0); 391 this.filter = filter; 392 } 393 394 public WritableRaster makeRaster(int w, int h) { 395 WritableRaster ras = makeRaster(colorModel, srcRas, w, h); 396 IntegerInterleavedRaster iiRas = (IntegerInterleavedRaster) ras; 397 outData = iiRas.getDataStorage(); 398 outSpan = iiRas.getScanlineStride(); 399 outOff = iiRas.getDataOffset(0); 400 return ras; 401 } 402 403 public void setRaster(int x, int y, int xerr, int yerr, 404 int w, int h, int bWidth, int bHeight, 405 int colincx, int colincxerr, 406 int colincy, int colincyerr, 407 int rowincx, int rowincxerr, 408 int rowincy, int rowincyerr) { 409 int[] inData = this.inData; 410 int[] outData = this.outData; 411 int out = outOff; 412 int inSpan = this.inSpan; 413 int inOff = this.inOff; 414 int outSpan = this.outSpan; 415 boolean filter = this.filter; 416 boolean normalx = (colincx == 1 && colincxerr == 0 && 417 colincy == 0 && colincyerr == 0) && !filter; 418 int rowx = x; 419 int rowy = y; 420 int rowxerr = xerr; 421 int rowyerr = yerr; 422 if (normalx) { 423 outSpan -= w; 424 } 425 int[] rgbs = filter ? new int[4] : null; 426 for (int j = 0; j < h; j++) { 427 if (normalx) { 428 int in = inOff + rowy * inSpan + bWidth; 429 x = bWidth - rowx; 430 out += w; 431 if (bWidth >= 32) { 432 int i = w; 433 while (i > 0) { 434 int copyw = (i < x) ? i : x; 435 System.arraycopy(inData, in - x, 436 outData, out - i, 437 copyw); 438 i -= copyw; 439 if ((x -= copyw) == 0) { 440 x = bWidth; 441 } 442 } 443 } else { 444 for (int i = w; i > 0; i--) { 445 outData[out - i] = inData[in - x]; 446 if (--x == 0) { 447 x = bWidth; 448 } 449 } 450 } 451 } else { 452 x = rowx; 453 y = rowy; 454 xerr = rowxerr; 455 yerr = rowyerr; 456 for (int i = 0; i < w; i++) { 457 if (filter) { 458 int nextx, nexty; 459 if ((nextx = x + 1) >= bWidth) { 460 nextx = 0; 461 } 462 if ((nexty = y + 1) >= bHeight) { 463 nexty = 0; 464 } 465 rgbs[0] = inData[inOff + y * inSpan + x]; 466 rgbs[1] = inData[inOff + y * inSpan + nextx]; 467 rgbs[2] = inData[inOff + nexty * inSpan + x]; 468 rgbs[3] = inData[inOff + nexty * inSpan + nextx]; 469 outData[out + i] = 470 TexturePaintContext.blend(rgbs, xerr, yerr); 471 } else { 472 outData[out + i] = inData[inOff + y * inSpan + x]; 473 } 474 if ((xerr += colincxerr) < 0) { 475 xerr &= Integer.MAX_VALUE; 476 x++; 477 } 478 if ((x += colincx) >= bWidth) { 479 x -= bWidth; 480 } 481 if ((yerr += colincyerr) < 0) { 482 yerr &= Integer.MAX_VALUE; 483 y++; 484 } 485 if ((y += colincy) >= bHeight) { 486 y -= bHeight; 487 } 488 } 489 } 490 if ((rowxerr += rowincxerr) < 0) { 491 rowxerr &= Integer.MAX_VALUE; 492 rowx++; 493 } 494 if ((rowx += rowincx) >= bWidth) { 495 rowx -= bWidth; 496 } 497 if ((rowyerr += rowincyerr) < 0) { 498 rowyerr &= Integer.MAX_VALUE; 499 rowy++; 500 } 501 if ((rowy += rowincy) >= bHeight) { 502 rowy -= bHeight; 503 } 504 out += outSpan; 505 } 506 } 507 } 508 509 static class Byte extends TexturePaintContext { 510 ByteInterleavedRaster srcRas; 511 byte[] inData; 512 int inOff; 513 int inSpan; 514 byte[] outData; 515 int outOff; 516 int outSpan; 517 518 public Byte(ByteInterleavedRaster srcRas, ColorModel cm, 519 AffineTransform xform, int maxw) 520 { 521 super(cm, xform, srcRas.getWidth(), srcRas.getHeight(), maxw); 522 this.srcRas = srcRas; 523 this.inData = srcRas.getDataStorage(); 524 this.inSpan = srcRas.getScanlineStride(); 525 this.inOff = srcRas.getDataOffset(0); 526 } 527 528 public WritableRaster makeRaster(int w, int h) { 529 WritableRaster ras = makeByteRaster(srcRas, w, h); 530 ByteInterleavedRaster biRas = (ByteInterleavedRaster) ras; 531 outData = biRas.getDataStorage(); 532 outSpan = biRas.getScanlineStride(); 533 outOff = biRas.getDataOffset(0); 534 return ras; 535 } 536 537 public void dispose() { 538 dropByteRaster(outRas); 539 } 540 541 public void setRaster(int x, int y, int xerr, int yerr, 542 int w, int h, int bWidth, int bHeight, 543 int colincx, int colincxerr, 544 int colincy, int colincyerr, 545 int rowincx, int rowincxerr, 546 int rowincy, int rowincyerr) { 547 byte[] inData = this.inData; 548 byte[] outData = this.outData; 549 int out = outOff; 550 int inSpan = this.inSpan; 551 int inOff = this.inOff; 552 int outSpan = this.outSpan; 553 boolean normalx = (colincx == 1 && colincxerr == 0 && 554 colincy == 0 && colincyerr == 0); 555 int rowx = x; 556 int rowy = y; 557 int rowxerr = xerr; 558 int rowyerr = yerr; 559 if (normalx) { 560 outSpan -= w; 561 } 562 for (int j = 0; j < h; j++) { 563 if (normalx) { 564 int in = inOff + rowy * inSpan + bWidth; 565 x = bWidth - rowx; 566 out += w; 567 if (bWidth >= 32) { 568 int i = w; 569 while (i > 0) { 570 int copyw = (i < x) ? i : x; 571 System.arraycopy(inData, in - x, 572 outData, out - i, 573 copyw); 574 i -= copyw; 575 if ((x -= copyw) == 0) { 576 x = bWidth; 577 } 578 } 579 } else { 580 for (int i = w; i > 0; i--) { 581 outData[out - i] = inData[in - x]; 582 if (--x == 0) { 583 x = bWidth; 584 } 585 } 586 } 587 } else { 588 x = rowx; 589 y = rowy; 590 xerr = rowxerr; 591 yerr = rowyerr; 592 for (int i = 0; i < w; i++) { 593 outData[out + i] = inData[inOff + y * inSpan + x]; 594 if ((xerr += colincxerr) < 0) { 595 xerr &= Integer.MAX_VALUE; 596 x++; 597 } 598 if ((x += colincx) >= bWidth) { 599 x -= bWidth; 600 } 601 if ((yerr += colincyerr) < 0) { 602 yerr &= Integer.MAX_VALUE; 603 y++; 604 } 605 if ((y += colincy) >= bHeight) { 606 y -= bHeight; 607 } 608 } 609 } 610 if ((rowxerr += rowincxerr) < 0) { 611 rowxerr &= Integer.MAX_VALUE; 612 rowx++; 613 } 614 if ((rowx += rowincx) >= bWidth) { 615 rowx -= bWidth; 616 } 617 if ((rowyerr += rowincyerr) < 0) { 618 rowyerr &= Integer.MAX_VALUE; 619 rowy++; 620 } 621 if ((rowy += rowincy) >= bHeight) { 622 rowy -= bHeight; 623 } 624 out += outSpan; 625 } 626 } 627 } 628 629 static class ByteFilter extends TexturePaintContext { 630 ByteInterleavedRaster srcRas; 631 int[] inPalette; 632 byte[] inData; 633 int inOff; 634 int inSpan; 635 int[] outData; 636 int outOff; 637 int outSpan; 638 639 public ByteFilter(ByteInterleavedRaster srcRas, ColorModel cm, 640 AffineTransform xform, int maxw) 641 { 642 super((cm.getTransparency() == Transparency.OPAQUE 643 ? xrgbmodel : argbmodel), 644 xform, srcRas.getWidth(), srcRas.getHeight(), maxw); 645 this.inPalette = new int[256]; 646 ((IndexColorModel) cm).getRGBs(this.inPalette); 647 this.srcRas = srcRas; 648 this.inData = srcRas.getDataStorage(); 649 this.inSpan = srcRas.getScanlineStride(); 650 this.inOff = srcRas.getDataOffset(0); 651 } 652 653 public WritableRaster makeRaster(int w, int h) { 654 // Note that we do not pass srcRas to makeRaster since it 655 // is a Byte Raster and this colorModel needs an Int Raster 656 WritableRaster ras = makeRaster(colorModel, null, w, h); 657 IntegerInterleavedRaster iiRas = (IntegerInterleavedRaster) ras; 658 outData = iiRas.getDataStorage(); 659 outSpan = iiRas.getScanlineStride(); 660 outOff = iiRas.getDataOffset(0); 661 return ras; 662 } 663 664 public void setRaster(int x, int y, int xerr, int yerr, 665 int w, int h, int bWidth, int bHeight, 666 int colincx, int colincxerr, 667 int colincy, int colincyerr, 668 int rowincx, int rowincxerr, 669 int rowincy, int rowincyerr) { 670 byte[] inData = this.inData; 671 int[] outData = this.outData; 672 int out = outOff; 673 int inSpan = this.inSpan; 674 int inOff = this.inOff; 675 int outSpan = this.outSpan; 676 int rowx = x; 677 int rowy = y; 678 int rowxerr = xerr; 679 int rowyerr = yerr; 680 int[] rgbs = new int[4]; 681 for (int j = 0; j < h; j++) { 682 x = rowx; 683 y = rowy; 684 xerr = rowxerr; 685 yerr = rowyerr; 686 for (int i = 0; i < w; i++) { 687 int nextx, nexty; 688 if ((nextx = x + 1) >= bWidth) { 689 nextx = 0; 690 } 691 if ((nexty = y + 1) >= bHeight) { 692 nexty = 0; 693 } 694 rgbs[0] = inPalette[0xff & inData[inOff + x + 695 inSpan * y]]; 696 rgbs[1] = inPalette[0xff & inData[inOff + nextx + 697 inSpan * y]]; 698 rgbs[2] = inPalette[0xff & inData[inOff + x + 699 inSpan * nexty]]; 700 rgbs[3] = inPalette[0xff & inData[inOff + nextx + 701 inSpan * nexty]]; 702 outData[out + i] = 703 TexturePaintContext.blend(rgbs, xerr, yerr); 704 if ((xerr += colincxerr) < 0) { 705 xerr &= Integer.MAX_VALUE; 706 x++; 707 } 708 if ((x += colincx) >= bWidth) { 709 x -= bWidth; 710 } 711 if ((yerr += colincyerr) < 0) { 712 yerr &= Integer.MAX_VALUE; 713 y++; 714 } 715 if ((y += colincy) >= bHeight) { 716 y -= bHeight; 717 } 718 } 719 if ((rowxerr += rowincxerr) < 0) { 720 rowxerr &= Integer.MAX_VALUE; 721 rowx++; 722 } 723 if ((rowx += rowincx) >= bWidth) { 724 rowx -= bWidth; 725 } 726 if ((rowyerr += rowincyerr) < 0) { 727 rowyerr &= Integer.MAX_VALUE; 728 rowy++; 729 } 730 if ((rowy += rowincy) >= bHeight) { 731 rowy -= bHeight; 732 } 733 out += outSpan; 734 } 735 } 736 } 737 738 static class Any extends TexturePaintContext { 739 WritableRaster srcRas; 740 boolean filter; 741 742 public Any(WritableRaster srcRas, ColorModel cm, 743 AffineTransform xform, int maxw, boolean filter) 744 { 745 super(cm, xform, srcRas.getWidth(), srcRas.getHeight(), maxw); 746 this.srcRas = srcRas; 747 this.filter = filter; 748 } 749 750 public WritableRaster makeRaster(int w, int h) { 751 return makeRaster(colorModel, srcRas, w, h); 752 } 753 754 public void setRaster(int x, int y, int xerr, int yerr, 755 int w, int h, int bWidth, int bHeight, 756 int colincx, int colincxerr, 757 int colincy, int colincyerr, 758 int rowincx, int rowincxerr, 759 int rowincy, int rowincyerr) { 760 Object data = null; 761 int rowx = x; 762 int rowy = y; 763 int rowxerr = xerr; 764 int rowyerr = yerr; 765 WritableRaster srcRas = this.srcRas; 766 WritableRaster outRas = this.outRas; 767 int[] rgbs = filter ? new int[4] : null; 768 for (int j = 0; j < h; j++) { 769 x = rowx; 770 y = rowy; 771 xerr = rowxerr; 772 yerr = rowyerr; 773 for (int i = 0; i < w; i++) { 774 data = srcRas.getDataElements(x, y, data); 775 if (filter) { 776 int nextx, nexty; 777 if ((nextx = x + 1) >= bWidth) { 778 nextx = 0; 779 } 780 if ((nexty = y + 1) >= bHeight) { 781 nexty = 0; 782 } 783 rgbs[0] = colorModel.getRGB(data); 784 data = srcRas.getDataElements(nextx, y, data); 785 rgbs[1] = colorModel.getRGB(data); 786 data = srcRas.getDataElements(x, nexty, data); 787 rgbs[2] = colorModel.getRGB(data); 788 data = srcRas.getDataElements(nextx, nexty, data); 789 rgbs[3] = colorModel.getRGB(data); 790 int rgb = 791 TexturePaintContext.blend(rgbs, xerr, yerr); 792 data = colorModel.getDataElements(rgb, data); 793 } 794 outRas.setDataElements(i, j, data); 795 if ((xerr += colincxerr) < 0) { 796 xerr &= Integer.MAX_VALUE; 797 x++; 798 } 799 if ((x += colincx) >= bWidth) { 800 x -= bWidth; 801 } 802 if ((yerr += colincyerr) < 0) { 803 yerr &= Integer.MAX_VALUE; 804 y++; 805 } 806 if ((y += colincy) >= bHeight) { 807 y -= bHeight; 808 } 809 } 810 if ((rowxerr += rowincxerr) < 0) { 811 rowxerr &= Integer.MAX_VALUE; 812 rowx++; 813 } 814 if ((rowx += rowincx) >= bWidth) { 815 rowx -= bWidth; 816 } 817 if ((rowyerr += rowincyerr) < 0) { 818 rowyerr &= Integer.MAX_VALUE; 819 rowy++; 820 } 821 if ((rowy += rowincy) >= bHeight) { 822 rowy -= bHeight; 823 } 824 } 825 } 826 } 827 }