1 /* 2 * Copyright (c) 1995, 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 sun.awt.image; 27 28 import java.awt.Color; 29 import java.awt.Graphics; 30 import java.awt.Transparency; 31 import java.awt.AWTException; 32 import java.awt.Rectangle; 33 import java.awt.image.BufferedImage; 34 import java.awt.image.ColorModel; 35 import java.awt.image.DirectColorModel; 36 import java.awt.image.IndexColorModel; 37 import java.awt.image.ImageConsumer; 38 import java.awt.image.ImageObserver; 39 import sun.awt.image.ByteComponentRaster; 40 import sun.awt.image.IntegerComponentRaster; 41 import java.awt.image.Raster; 42 import java.awt.image.WritableRaster; 43 import java.awt.image.DataBuffer; 44 import java.awt.image.DataBufferInt; 45 import java.awt.Graphics2D; 46 import java.awt.geom.AffineTransform; 47 import sun.awt.image.ImageWatched; 48 import java.util.Hashtable; 49 50 public class ImageRepresentation extends ImageWatched implements ImageConsumer 51 { 52 InputStreamImageSource src; 53 ToolkitImage image; 54 int tag; 55 56 long pData; // used by windows native code only -- internal state REMIND ATTN @@ 57 58 int width = -1; 59 int height = -1; 60 int hints; 61 62 int availinfo; 63 64 Rectangle newbits; 65 66 BufferedImage bimage; 67 WritableRaster biRaster; 68 protected ColorModel cmodel; 69 ColorModel srcModel = null; 70 int[] srcLUT = null; 71 int srcLUTtransIndex = -1; 72 int numSrcLUT = 0; 73 boolean forceCMhint; 74 int sstride; 75 boolean isDefaultBI = false; 76 boolean isSameCM = false; 77 initIDs()78 private static native void initIDs(); 79 80 static { 81 /* ensure that the necessary native libraries are loaded */ NativeLibLoader.loadLibraries()82 NativeLibLoader.loadLibraries(); initIDs()83 initIDs(); 84 } 85 86 /** 87 * Create an ImageRepresentation for the given Image. The 88 * width and height are unknown at this point. The color 89 * model is a hint as to the color model to use when creating 90 * the buffered image. If null, the src color model will 91 * be used. 92 */ ImageRepresentation(ToolkitImage im, ColorModel cmodel, boolean forceCMhint)93 public ImageRepresentation(ToolkitImage im, ColorModel cmodel, boolean 94 forceCMhint) { 95 image = im; 96 97 if (image.getSource() instanceof InputStreamImageSource) { 98 src = (InputStreamImageSource) image.getSource(); 99 } 100 101 setColorModel(cmodel); 102 103 this.forceCMhint = forceCMhint; 104 } 105 106 /* REMIND: Only used for Frame.setIcon - should use ImageWatcher instead */ reconstruct(int flags)107 public synchronized void reconstruct(int flags) { 108 if (src != null) { 109 src.checkSecurity(null, false); 110 } 111 int missinginfo = flags & ~availinfo; 112 if ((availinfo & ImageObserver.ERROR) == 0 && missinginfo != 0) { 113 numWaiters++; 114 try { 115 startProduction(); 116 missinginfo = flags & ~availinfo; 117 while ((availinfo & ImageObserver.ERROR) == 0 && 118 missinginfo != 0) 119 { 120 try { 121 wait(); 122 } catch (InterruptedException e) { 123 Thread.currentThread().interrupt(); 124 return; 125 } 126 missinginfo = flags & ~availinfo; 127 } 128 } finally { 129 decrementWaiters(); 130 } 131 } 132 } 133 setDimensions(int w, int h)134 public void setDimensions(int w, int h) { 135 if (src != null) { 136 src.checkSecurity(null, false); 137 } 138 139 image.setDimensions(w, h); 140 141 newInfo(image, (ImageObserver.WIDTH | ImageObserver.HEIGHT), 142 0, 0, w, h); 143 144 if (w <= 0 || h <= 0) { 145 imageComplete(ImageConsumer.IMAGEERROR); 146 return; 147 } 148 149 if (width != w || height != h) { 150 // dimension mismatch => trigger recreation of the buffer 151 bimage = null; 152 } 153 154 width = w; 155 height = h; 156 157 availinfo |= ImageObserver.WIDTH | ImageObserver.HEIGHT; 158 } 159 getWidth()160 public int getWidth() { 161 return width; 162 } 163 getHeight()164 public int getHeight() { 165 return height; 166 } 167 getColorModel()168 ColorModel getColorModel() { 169 return cmodel; 170 } 171 getBufferedImage()172 BufferedImage getBufferedImage() { 173 return bimage; 174 } 175 176 /** 177 * Returns the BufferedImage that will be used as the representation of 178 * the pixel data. Subclasses can override this method to return 179 * platform specific subclasses of BufferedImage that may or may not be 180 * accelerated. 181 * 182 * It is subclass' responsibility to propagate acceleration priority 183 * to the newly created image. 184 */ createImage(ColorModel cm, WritableRaster raster, boolean isRasterPremultiplied, Hashtable<?,?> properties)185 protected BufferedImage createImage(ColorModel cm, 186 WritableRaster raster, 187 boolean isRasterPremultiplied, 188 Hashtable<?,?> properties) 189 { 190 BufferedImage bi = 191 new BufferedImage(cm, raster, isRasterPremultiplied, null); 192 bi.setAccelerationPriority(image.getAccelerationPriority()); 193 return bi; 194 } 195 setProperties(Hashtable<?,?> props)196 public void setProperties(Hashtable<?,?> props) { 197 if (src != null) { 198 src.checkSecurity(null, false); 199 } 200 image.setProperties(props); 201 newInfo(image, ImageObserver.PROPERTIES, 0, 0, 0, 0); 202 } 203 setColorModel(ColorModel model)204 public void setColorModel(ColorModel model) { 205 if (src != null) { 206 src.checkSecurity(null, false); 207 } 208 srcModel = model; 209 210 // Check to see if model is INT_RGB 211 if (model instanceof IndexColorModel) { 212 if (model.getTransparency() == Transparency.TRANSLUCENT) { 213 // REMIND: 214 // Probably need to composite anyway so force ARGB 215 cmodel = ColorModel.getRGBdefault(); 216 srcLUT = null; 217 } 218 else { 219 IndexColorModel icm = (IndexColorModel) model; 220 numSrcLUT = icm.getMapSize(); 221 srcLUT = new int[Math.max(numSrcLUT, 256)]; 222 icm.getRGBs(srcLUT); 223 srcLUTtransIndex = icm.getTransparentPixel(); 224 cmodel = model; 225 } 226 } 227 else { 228 if (cmodel == null) { 229 cmodel = model; 230 srcLUT = null; 231 } 232 else if (model instanceof DirectColorModel) { 233 // If it is INT_RGB or INT_ARGB, use the model 234 DirectColorModel dcm = (DirectColorModel) model; 235 if ((dcm.getRedMask() == 0xff0000) && 236 (dcm.getGreenMask() == 0xff00) && 237 (dcm.getBlueMask() == 0x00ff)) { 238 cmodel = model; 239 srcLUT = null; 240 } 241 } 242 } 243 244 isSameCM = (cmodel == model); 245 } 246 createBufferedImage()247 void createBufferedImage() { 248 // REMIND: Be careful! Is this called everytime there is a 249 // startProduction? We only want to call it if it is new or 250 // there is an error 251 isDefaultBI = false; 252 try { 253 biRaster = cmodel.createCompatibleWritableRaster(width, height); 254 bimage = createImage(cmodel, biRaster, 255 cmodel.isAlphaPremultiplied(), null); 256 } catch (Exception e) { 257 // Create a default image 258 cmodel = ColorModel.getRGBdefault(); 259 biRaster = cmodel.createCompatibleWritableRaster(width, height); 260 bimage = createImage(cmodel, biRaster, false, null); 261 } 262 int type = bimage.getType(); 263 264 if ((cmodel == ColorModel.getRGBdefault()) || 265 (type == BufferedImage.TYPE_INT_RGB) || 266 (type == BufferedImage.TYPE_INT_ARGB_PRE)) { 267 isDefaultBI = true; 268 } 269 else if (cmodel instanceof DirectColorModel) { 270 DirectColorModel dcm = (DirectColorModel) cmodel; 271 if (dcm.getRedMask() == 0xff0000 && 272 dcm.getGreenMask() == 0xff00 && 273 dcm.getBlueMask() == 0xff) { 274 isDefaultBI = true; 275 } 276 } 277 } 278 convertToRGB()279 private void convertToRGB() { 280 int w = bimage.getWidth(); 281 int h = bimage.getHeight(); 282 int size = w*h; 283 284 DataBufferInt dbi = new DataBufferInt(size); 285 // Note that stealData() requires a markDirty() afterwards 286 // since we modify the data in it. 287 int[] newpixels = SunWritableRaster.stealData(dbi, 0); 288 if (cmodel instanceof IndexColorModel && 289 biRaster instanceof ByteComponentRaster && 290 biRaster.getNumDataElements() == 1) 291 { 292 ByteComponentRaster bct = (ByteComponentRaster) biRaster; 293 byte[] data = bct.getDataStorage(); 294 int coff = bct.getDataOffset(0); 295 for (int i=0; i < size; i++) { 296 newpixels[i] = srcLUT[data[coff+i]&0xff]; 297 } 298 } 299 else { 300 Object srcpixels = null; 301 int off=0; 302 for (int y=0; y < h; y++) { 303 for (int x=0; x < w; x++) { 304 srcpixels=biRaster.getDataElements(x, y, srcpixels); 305 newpixels[off++] = cmodel.getRGB(srcpixels); 306 } 307 } 308 } 309 // We modified the data array directly above so mark it as dirty now... 310 SunWritableRaster.markDirty(dbi); 311 312 isSameCM = false; 313 cmodel = ColorModel.getRGBdefault(); 314 315 int[] bandMasks = {0x00ff0000, 316 0x0000ff00, 317 0x000000ff, 318 0xff000000}; 319 320 biRaster = Raster.createPackedRaster(dbi,w,h,w, 321 bandMasks,null); 322 323 bimage = createImage(cmodel, biRaster, 324 cmodel.isAlphaPremultiplied(), null); 325 srcLUT = null; 326 isDefaultBI = true; 327 } 328 setHints(int h)329 public void setHints(int h) { 330 if (src != null) { 331 src.checkSecurity(null, false); 332 } 333 hints = h; 334 } 335 setICMpixels(int x, int y, int w, int h, int[] lut, byte[] pix, int off, int scansize, IntegerComponentRaster ict)336 private native boolean setICMpixels(int x, int y, int w, int h, int[] lut, 337 byte[] pix, int off, int scansize, 338 IntegerComponentRaster ict); setDiffICM(int x, int y, int w, int h, int[] lut, int transPix, int numLut, IndexColorModel icm, byte[] pix, int off, int scansize, ByteComponentRaster bct, int chanOff)339 private native boolean setDiffICM(int x, int y, int w, int h, int[] lut, 340 int transPix, int numLut, IndexColorModel icm, 341 byte[] pix, int off, int scansize, 342 ByteComponentRaster bct, int chanOff); 343 static boolean s_useNative = true; 344 setPixels(int x, int y, int w, int h, ColorModel model, byte[] pix, int off, int scansize)345 public void setPixels(int x, int y, int w, int h, 346 ColorModel model, 347 byte[] pix, int off, int scansize) { 348 int lineOff=off; 349 int poff; 350 int[] newLUT=null; 351 352 if (src != null) { 353 src.checkSecurity(null, false); 354 } 355 356 // REMIND: What if the model doesn't fit in default color model? 357 synchronized (this) { 358 if (bimage == null) { 359 if (cmodel == null) { 360 cmodel = model; 361 } 362 createBufferedImage(); 363 } 364 365 if (w <= 0 || h <= 0) { 366 return; 367 } 368 369 int biWidth = biRaster.getWidth(); 370 int biHeight = biRaster.getHeight(); 371 372 int x1 = x+w; // Overflow protection below 373 int y1 = y+h; // Overflow protection below 374 if (x < 0) { 375 off -= x; 376 x = 0; 377 } else if (x1 < 0) { 378 x1 = biWidth; // Must be overflow 379 } 380 if (y < 0) { 381 off -= y*scansize; 382 y = 0; 383 } else if (y1 < 0) { 384 y1 = biHeight; // Must be overflow 385 } 386 if (x1 > biWidth) { 387 x1 = biWidth; 388 } 389 if (y1 > biHeight) { 390 y1 = biHeight; 391 } 392 if (x >= x1 || y >= y1) { 393 return; 394 } 395 // x,y,x1,y1 are all >= 0, so w,h must be >= 0 396 w = x1-x; 397 h = y1-y; 398 // off is first pixel read so it must be in bounds 399 if (off < 0 || off >= pix.length) { 400 // They overflowed their own array 401 throw new ArrayIndexOutOfBoundsException("Data offset out of bounds."); 402 } 403 // pix.length and off are >= 0 so remainder >= 0 404 int remainder = pix.length - off; 405 if (remainder < w) { 406 // They overflowed their own array 407 throw new ArrayIndexOutOfBoundsException("Data array is too short."); 408 } 409 int num; 410 if (scansize < 0) { 411 num = (off / -scansize) + 1; 412 } else if (scansize > 0) { 413 num = ((remainder-w) / scansize) + 1; 414 } else { 415 num = h; 416 } 417 if (h > num) { 418 // They overflowed their own array. 419 throw new ArrayIndexOutOfBoundsException("Data array is too short."); 420 } 421 422 if (isSameCM && (cmodel != model) && (srcLUT != null) && 423 (model instanceof IndexColorModel) && 424 (biRaster instanceof ByteComponentRaster)) 425 { 426 IndexColorModel icm = (IndexColorModel) model; 427 ByteComponentRaster bct = (ByteComponentRaster) biRaster; 428 int numlut = numSrcLUT; 429 if (!setDiffICM(x, y, w, h, srcLUT, srcLUTtransIndex, 430 numSrcLUT, icm, 431 pix, off, scansize, bct, 432 bct.getDataOffset(0))) { 433 convertToRGB(); 434 } 435 else { 436 // Note that setDiffICM modified the raster directly 437 // so we must mark it as changed 438 bct.markDirty(); 439 if (numlut != numSrcLUT) { 440 boolean hasAlpha = icm.hasAlpha(); 441 if (srcLUTtransIndex != -1) { 442 hasAlpha = true; 443 } 444 int nbits = icm.getPixelSize(); 445 icm = new IndexColorModel(nbits, 446 numSrcLUT, srcLUT, 447 0, hasAlpha, 448 srcLUTtransIndex, 449 (nbits > 8 450 ? DataBuffer.TYPE_USHORT 451 : DataBuffer.TYPE_BYTE)); 452 cmodel = icm; 453 bimage = createImage(icm, bct, false, null); 454 } 455 return; 456 } 457 } 458 459 if (isDefaultBI) { 460 int pixel; 461 IntegerComponentRaster iraster = 462 (IntegerComponentRaster) biRaster; 463 if (srcLUT != null && model instanceof IndexColorModel) { 464 if (model != srcModel) { 465 // Fill in the new lut 466 ((IndexColorModel)model).getRGBs(srcLUT); 467 srcModel = model; 468 } 469 470 if (s_useNative) { 471 // Note that setICMpixels modifies the raster directly 472 // so we must mark it as changed afterwards 473 if (setICMpixels(x, y, w, h, srcLUT, pix, off, scansize, 474 iraster)) 475 { 476 iraster.markDirty(); 477 } else { 478 abort(); 479 return; 480 } 481 } 482 else { 483 int[] storage = new int[w*h]; 484 int soff = 0; 485 // It is an IndexColorModel 486 for (int yoff=0; yoff < h; yoff++, 487 lineOff += scansize) { 488 poff = lineOff; 489 for (int i=0; i < w; i++) { 490 storage[soff++] = srcLUT[pix[poff++]&0xff]; 491 } 492 } 493 iraster.setDataElements(x, y, w, h, storage); 494 } 495 } 496 else { 497 int[] storage = new int[w]; 498 for (int yoff=y; yoff < y+h; yoff++, lineOff += scansize) { 499 poff = lineOff; 500 for (int i=0; i < w; i++) { 501 storage[i] = model.getRGB(pix[poff++]&0xff); 502 } 503 iraster.setDataElements(x, yoff, w, 1, storage); 504 } 505 availinfo |= ImageObserver.SOMEBITS; 506 } 507 } 508 else if ((cmodel == model) && 509 (biRaster instanceof ByteComponentRaster) && 510 (biRaster.getNumDataElements() == 1)){ 511 ByteComponentRaster bt = (ByteComponentRaster) biRaster; 512 if (off == 0 && scansize == w) { 513 bt.putByteData(x, y, w, h, pix); 514 } 515 else { 516 byte[] bpix = new byte[w]; 517 poff = off; 518 for (int yoff=y; yoff < y+h; yoff++) { 519 System.arraycopy(pix, poff, bpix, 0, w); 520 bt.putByteData(x, yoff, w, 1, bpix); 521 poff += scansize; 522 } 523 } 524 } 525 else { 526 for (int yoff=y; yoff < y+h; yoff++, lineOff += scansize) { 527 poff = lineOff; 528 for (int xoff=x; xoff < x+w; xoff++) { 529 bimage.setRGB(xoff, yoff, 530 model.getRGB(pix[poff++]&0xff)); 531 } 532 } 533 availinfo |= ImageObserver.SOMEBITS; 534 } 535 } 536 537 if ((availinfo & ImageObserver.FRAMEBITS) == 0) { 538 newInfo(image, ImageObserver.SOMEBITS, x, y, w, h); 539 } 540 } 541 542 setPixels(int x, int y, int w, int h, ColorModel model, int[] pix, int off, int scansize)543 public void setPixels(int x, int y, int w, int h, ColorModel model, 544 int[] pix, int off, int scansize) 545 { 546 int lineOff=off; 547 int poff; 548 549 if (src != null) { 550 src.checkSecurity(null, false); 551 } 552 553 // REMIND: What if the model doesn't fit in default color model? 554 synchronized (this) { 555 if (bimage == null) { 556 if (cmodel == null) { 557 cmodel = model; 558 } 559 createBufferedImage(); 560 } 561 562 int[] storage = new int[w]; 563 int yoff; 564 int pixel; 565 566 if (cmodel instanceof IndexColorModel) { 567 // REMIND: Right now we don't support writing back into ICM 568 // images. 569 convertToRGB(); 570 } 571 572 if ((model == cmodel) && 573 (biRaster instanceof IntegerComponentRaster)) { 574 IntegerComponentRaster iraster = 575 (IntegerComponentRaster) biRaster; 576 577 if (off == 0 && scansize == w) { 578 iraster.setDataElements(x, y, w, h, pix); 579 } 580 else { 581 // Need to pack the data 582 for (yoff=y; yoff < y+h; yoff++, lineOff+=scansize) { 583 System.arraycopy(pix, lineOff, storage, 0, w); 584 iraster.setDataElements(x, yoff, w, 1, storage); 585 } 586 } 587 } 588 else { 589 if (model.getTransparency() != Transparency.OPAQUE && 590 cmodel.getTransparency() == Transparency.OPAQUE) { 591 convertToRGB(); 592 } 593 594 if (isDefaultBI) { 595 IntegerComponentRaster iraster = 596 (IntegerComponentRaster) biRaster; 597 int[] data = iraster.getDataStorage(); 598 if (cmodel.equals(model)) { 599 int sstride = iraster.getScanlineStride(); 600 int doff = y*sstride + x; 601 for (yoff=0; yoff < h; yoff++, lineOff += scansize) { 602 System.arraycopy(pix, lineOff, data, doff, w); 603 doff += sstride; 604 } 605 // Note: manual modification of pixels, mark the 606 // raster as changed 607 iraster.markDirty(); 608 } 609 else { 610 for (yoff=y; yoff < y+h; yoff++, lineOff += scansize) { 611 poff = lineOff; 612 for (int i=0; i < w; i++) { 613 storage[i]=model.getRGB(pix[poff++]); 614 } 615 iraster.setDataElements(x, yoff, w, 1, storage); 616 } 617 } 618 619 availinfo |= ImageObserver.SOMEBITS; 620 } 621 else { 622 Object tmp = null; 623 624 for (yoff=y; yoff < y+h; yoff++, lineOff += scansize) { 625 poff = lineOff; 626 for (int xoff=x; xoff < x+w; xoff++) { 627 pixel = model.getRGB(pix[poff++]); 628 tmp = cmodel.getDataElements(pixel,tmp); 629 biRaster.setDataElements(xoff, yoff,tmp); 630 } 631 } 632 availinfo |= ImageObserver.SOMEBITS; 633 } 634 } 635 } 636 637 // Can't do this here since we might need to transform/clip 638 // the region 639 if (((availinfo & ImageObserver.FRAMEBITS) == 0)) { 640 newInfo(image, ImageObserver.SOMEBITS, x, y, w, h); 641 } 642 } 643 getOpaqueRGBImage()644 public BufferedImage getOpaqueRGBImage() { 645 if (bimage.getType() == BufferedImage.TYPE_INT_ARGB) { 646 int w = bimage.getWidth(); 647 int h = bimage.getHeight(); 648 int size = w * h; 649 650 // Note that we steal the data array here, but only for reading... 651 DataBufferInt db = (DataBufferInt)biRaster.getDataBuffer(); 652 int[] pixels = SunWritableRaster.stealData(db, 0); 653 654 for (int i = 0; i < size; i++) { 655 if ((pixels[i] >>> 24) != 0xff) { 656 return bimage; 657 } 658 } 659 660 ColorModel opModel = new DirectColorModel(24, 661 0x00ff0000, 662 0x0000ff00, 663 0x000000ff); 664 665 int[] bandmasks = {0x00ff0000, 0x0000ff00, 0x000000ff}; 666 WritableRaster opRaster = Raster.createPackedRaster(db, w, h, w, 667 bandmasks, 668 null); 669 670 try { 671 BufferedImage opImage = createImage(opModel, opRaster, 672 false, null); 673 return opImage; 674 } catch (Exception e) { 675 return bimage; 676 } 677 } 678 return bimage; 679 } 680 681 private boolean consuming = false; 682 imageComplete(int status)683 public void imageComplete(int status) { 684 if (src != null) { 685 src.checkSecurity(null, false); 686 } 687 boolean done; 688 int info; 689 switch (status) { 690 default: 691 case ImageConsumer.IMAGEABORTED: 692 done = true; 693 info = ImageObserver.ABORT; 694 break; 695 case ImageConsumer.IMAGEERROR: 696 image.addInfo(ImageObserver.ERROR); 697 done = true; 698 info = ImageObserver.ERROR; 699 dispose(); 700 break; 701 case ImageConsumer.STATICIMAGEDONE: 702 done = true; 703 info = ImageObserver.ALLBITS; 704 break; 705 case ImageConsumer.SINGLEFRAMEDONE: 706 done = false; 707 info = ImageObserver.FRAMEBITS; 708 break; 709 } 710 synchronized (this) { 711 if (done) { 712 image.getSource().removeConsumer(this); 713 consuming = false; 714 newbits = null; 715 716 if (bimage != null) { 717 bimage = getOpaqueRGBImage(); 718 } 719 } 720 availinfo |= info; 721 notifyAll(); 722 } 723 724 newInfo(image, info, 0, 0, width, height); 725 726 image.infoDone(status); 727 } 728 startProduction()729 /*synchronized*/ void startProduction() { 730 if (!consuming) { 731 consuming = true; 732 image.getSource().startProduction(this); 733 } 734 } 735 736 private int numWaiters; 737 checkConsumption()738 private synchronized void checkConsumption() { 739 if (isWatcherListEmpty() && numWaiters == 0 && 740 ((availinfo & ImageObserver.ALLBITS) == 0)) 741 { 742 dispose(); 743 } 744 } 745 notifyWatcherListEmpty()746 public synchronized void notifyWatcherListEmpty() { 747 checkConsumption(); 748 } 749 decrementWaiters()750 private synchronized void decrementWaiters() { 751 --numWaiters; 752 checkConsumption(); 753 } 754 prepare(ImageObserver iw)755 public boolean prepare(ImageObserver iw) { 756 if (src != null) { 757 src.checkSecurity(null, false); 758 } 759 if ((availinfo & ImageObserver.ERROR) != 0) { 760 if (iw != null) { 761 iw.imageUpdate(image, ImageObserver.ERROR|ImageObserver.ABORT, 762 -1, -1, -1, -1); 763 } 764 return false; 765 } 766 boolean done = ((availinfo & ImageObserver.ALLBITS) != 0); 767 if (!done) { 768 addWatcher(iw); 769 startProduction(); 770 // Some producers deliver image data synchronously 771 done = ((availinfo & ImageObserver.ALLBITS) != 0); 772 } 773 return done; 774 } 775 check(ImageObserver iw)776 public int check(ImageObserver iw) { 777 778 if (src != null) { 779 src.checkSecurity(null, false); 780 } 781 if ((availinfo & (ImageObserver.ERROR | ImageObserver.ALLBITS)) == 0) { 782 addWatcher(iw); 783 } 784 785 return availinfo; 786 } 787 drawToBufImage(Graphics g, ToolkitImage img, int x, int y, Color bg, ImageObserver iw)788 public boolean drawToBufImage(Graphics g, ToolkitImage img, 789 int x, int y, Color bg, 790 ImageObserver iw) { 791 792 if (src != null) { 793 src.checkSecurity(null, false); 794 } 795 if ((availinfo & ImageObserver.ERROR) != 0) { 796 if (iw != null) { 797 iw.imageUpdate(image, ImageObserver.ERROR|ImageObserver.ABORT, 798 -1, -1, -1, -1); 799 } 800 return false; 801 } 802 boolean done = ((availinfo & ImageObserver.ALLBITS) != 0); 803 boolean abort = ((availinfo & ImageObserver.ABORT) != 0); 804 805 if (!done && !abort) { 806 addWatcher(iw); 807 startProduction(); 808 // Some producers deliver image data synchronously 809 done = ((availinfo & ImageObserver.ALLBITS) != 0); 810 } 811 812 if (done || (0 != (availinfo & ImageObserver.FRAMEBITS))) { 813 g.drawImage (bimage, x, y, bg, null); 814 } 815 816 return done; 817 } 818 drawToBufImage(Graphics g, ToolkitImage img, int x, int y, int w, int h, Color bg, ImageObserver iw)819 public boolean drawToBufImage(Graphics g, ToolkitImage img, 820 int x, int y, int w, int h, 821 Color bg, ImageObserver iw) { 822 823 if (src != null) { 824 src.checkSecurity(null, false); 825 } 826 if ((availinfo & ImageObserver.ERROR) != 0) { 827 if (iw != null) { 828 iw.imageUpdate(image, ImageObserver.ERROR|ImageObserver.ABORT, 829 -1, -1, -1, -1); 830 } 831 return false; 832 } 833 834 boolean done = ((availinfo & ImageObserver.ALLBITS) != 0); 835 boolean abort = ((availinfo & ImageObserver.ABORT) != 0); 836 837 if (!done && !abort) { 838 addWatcher(iw); 839 startProduction(); 840 // Some producers deliver image data synchronously 841 done = ((availinfo & ImageObserver.ALLBITS) != 0); 842 } 843 844 if (done || (0 != (availinfo & ImageObserver.FRAMEBITS))) { 845 g.drawImage (bimage, x, y, w, h, bg, null); 846 } 847 848 return done; 849 } 850 drawToBufImage(Graphics g, ToolkitImage img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, Color bg, ImageObserver iw)851 public boolean drawToBufImage(Graphics g, ToolkitImage img, 852 int dx1, int dy1, int dx2, int dy2, 853 int sx1, int sy1, int sx2, int sy2, 854 Color bg, ImageObserver iw) { 855 856 if (src != null) { 857 src.checkSecurity(null, false); 858 } 859 if ((availinfo & ImageObserver.ERROR) != 0) { 860 if (iw != null) { 861 iw.imageUpdate(image, ImageObserver.ERROR|ImageObserver.ABORT, 862 -1, -1, -1, -1); 863 } 864 return false; 865 } 866 boolean done = ((availinfo & ImageObserver.ALLBITS) != 0); 867 boolean abort = ((availinfo & ImageObserver.ABORT) != 0); 868 869 if (!done && !abort) { 870 addWatcher(iw); 871 startProduction(); 872 // Some producers deliver image data synchronously 873 done = ((availinfo & ImageObserver.ALLBITS) != 0); 874 } 875 876 if (done || (0 != (availinfo & ImageObserver.FRAMEBITS))) { 877 g.drawImage (bimage, 878 dx1, dy1, dx2, dy2, 879 sx1, sy1, sx2, sy2, 880 bg, null); 881 } 882 883 return done; 884 } 885 drawToBufImage(Graphics g, ToolkitImage img, AffineTransform xform, ImageObserver iw)886 public boolean drawToBufImage(Graphics g, ToolkitImage img, 887 AffineTransform xform, 888 ImageObserver iw) 889 { 890 Graphics2D g2 = (Graphics2D) g; 891 892 if (src != null) { 893 src.checkSecurity(null, false); 894 } 895 if ((availinfo & ImageObserver.ERROR) != 0) { 896 if (iw != null) { 897 iw.imageUpdate(image, ImageObserver.ERROR|ImageObserver.ABORT, 898 -1, -1, -1, -1); 899 } 900 return false; 901 } 902 boolean done = ((availinfo & ImageObserver.ALLBITS) != 0); 903 boolean abort = ((availinfo & ImageObserver.ABORT) != 0); 904 905 if (!done && !abort) { 906 addWatcher(iw); 907 startProduction(); 908 // Some producers deliver image data synchronously 909 done = ((availinfo & ImageObserver.ALLBITS) != 0); 910 } 911 912 if (done || (0 != (availinfo & ImageObserver.FRAMEBITS))) { 913 g2.drawImage (bimage, xform, null); 914 } 915 916 return done; 917 } 918 abort()919 synchronized void abort() { 920 image.getSource().removeConsumer(this); 921 consuming = false; 922 newbits = null; 923 bimage = null; 924 biRaster = null; 925 cmodel = null; 926 srcLUT = null; 927 isDefaultBI = false; 928 isSameCM = false; 929 930 newInfo(image, ImageObserver.ABORT, -1, -1, -1, -1); 931 availinfo &= ~(ImageObserver.SOMEBITS 932 | ImageObserver.FRAMEBITS 933 | ImageObserver.ALLBITS 934 | ImageObserver.ERROR); 935 } 936 dispose()937 synchronized void dispose() { 938 image.getSource().removeConsumer(this); 939 consuming = false; 940 newbits = null; 941 availinfo &= ~(ImageObserver.SOMEBITS 942 | ImageObserver.FRAMEBITS 943 | ImageObserver.ALLBITS); 944 } 945 setAccelerationPriority(float priority)946 public void setAccelerationPriority(float priority) { 947 if (bimage != null) { 948 bimage.setAccelerationPriority(priority); 949 } 950 } 951 } 952