1 /*
   2  * Copyright (c) 2011, 2012, 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.java2d;
  27 
  28 import java.awt.*;
  29 import java.awt.color.*;
  30 import java.awt.image.*;
  31 import java.nio.*;
  32 
  33 import sun.awt.image.*;
  34 import sun.java2d.loops.*;
  35 
  36 public class OSXOffScreenSurfaceData extends OSXSurfaceData // implements RasterListener
  37 {
  38     private static native void initIDs();
  39 
  40     static {
  41         initIDs();
  42     }
  43 
  44     // the image associated with this surface
  45     BufferedImage bim;
  46     // the image associated with this custom surface
  47     BufferedImage bimBackup;
  48     // <rdar://problem/4177639> nio based images use ARGB_PRE
  49     static DirectColorModel dcmBackup = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000, true, DataBuffer.TYPE_INT);
  50 
  51     Object lock;
  52 
  53     // cached rasters for easy access
  54     WritableRaster bufImgRaster;
  55     SunWritableRaster bufImgSunRaster;
  56 
  57     // these are extra image types we can handle
  58     private static final int TYPE_3BYTE_RGB = BufferedImage.TYPE_BYTE_INDEXED + 1;
  59 
  60     // these are for callbacks when pixes have been touched
  61     protected ByteBuffer fImageInfo;
  62     IntBuffer fImageInfoInt;
  63     private static final int kNeedToSyncFromJavaPixelsIndex = 0;
  64     private static final int kNativePixelsChangedIndex = 1;
  65     private static final int kImageStolenIndex = 2;
  66     private static final int kSizeOfParameters = kImageStolenIndex + 1;
  67 
  68     public static native SurfaceData getSurfaceData(BufferedImage bufImg);
  69 
  70     protected static native void setSurfaceData(BufferedImage bufImg, SurfaceData sData);
  71 
  72     public static SurfaceData createData(BufferedImage bufImg) {
  73         /*
  74          * if ((bufImg.getWidth() == 32) && (bufImg.getHeight() == 32)) { Thread.dumpStack(); }
  75          */
  76         // This could be called from multiple threads. We need to synchronized on the image so that
  77         // we can ensure that only one surface data is created per image. (<rdar://4564873>)
  78         // Note: Eventually, we should switch to using the same mechanism (CachingSurfaceManager) that Sun uses
  79         // <rdar://4563741>
  80         synchronized (bufImg) {
  81             SurfaceData sData = getSurfaceData(bufImg);
  82             if (sData != null) { return sData; }
  83 
  84             OSXOffScreenSurfaceData osData = OSXOffScreenSurfaceData.createNewSurface(bufImg);
  85 
  86             OSXOffScreenSurfaceData.setSurfaceData(bufImg, osData);
  87             osData.cacheRasters(bufImg);
  88 //            osData.setRasterListener();
  89 
  90             return osData;
  91         }
  92     }
  93 
  94     public static SurfaceData createData(Raster ras, ColorModel cm) {
  95         throw new InternalError("SurfaceData not implemented for Raster/CM");
  96     }
  97 
  98     static OSXOffScreenSurfaceData createNewSurface(BufferedImage bufImg) {
  99         SurfaceData sData = null;
 100 
 101         ColorModel cm = bufImg.getColorModel();
 102         int type = bufImg.getType();
 103         // REMIND: Check the image type and pick an appropriate subclass
 104         switch (type) {
 105             case BufferedImage.TYPE_INT_BGR:
 106                 sData = createDataIC(bufImg, SurfaceType.IntBgr);
 107                 break;
 108             case BufferedImage.TYPE_INT_RGB:
 109                 sData = createDataIC(bufImg, SurfaceType.IntRgb);
 110                 break;
 111             case BufferedImage.TYPE_INT_ARGB:
 112                 sData = createDataIC(bufImg, SurfaceType.IntArgb);
 113                 break;
 114             case BufferedImage.TYPE_INT_ARGB_PRE:
 115                 sData = createDataIC(bufImg, SurfaceType.IntArgbPre);
 116                 break;
 117             case BufferedImage.TYPE_3BYTE_BGR:
 118                 sData = createDataBC(bufImg, SurfaceType.ThreeByteBgr, 2);
 119                 break;
 120             case BufferedImage.TYPE_4BYTE_ABGR:
 121                 sData = createDataBC(bufImg, SurfaceType.FourByteAbgr, 3);
 122                 break;
 123             case BufferedImage.TYPE_4BYTE_ABGR_PRE:
 124                 sData = createDataBC(bufImg, SurfaceType.FourByteAbgrPre, 3);
 125                 break;
 126             case BufferedImage.TYPE_USHORT_565_RGB:
 127                 sData = createDataSC(bufImg, SurfaceType.Ushort565Rgb, null);
 128                 break;
 129             case BufferedImage.TYPE_USHORT_555_RGB:
 130                 sData = createDataSC(bufImg, SurfaceType.Ushort555Rgb, null);
 131                 break;
 132             case BufferedImage.TYPE_BYTE_INDEXED: {
 133                 SurfaceType sType;
 134                 switch (cm.getTransparency()) {
 135                     case OPAQUE:
 136                         if (isOpaqueGray((IndexColorModel) cm)) {
 137                             sType = SurfaceType.Index8Gray;
 138                         } else {
 139                             sType = SurfaceType.ByteIndexedOpaque;
 140                         }
 141                         break;
 142                     case BITMASK:
 143                         sType = SurfaceType.ByteIndexedBm;
 144                         break;
 145                     case TRANSLUCENT:
 146                         sType = SurfaceType.ByteIndexed;
 147                         break;
 148                     default:
 149                         throw new InternalError("Unrecognized transparency");
 150                 }
 151                 sData = createDataBC(bufImg, sType, 0);
 152             }
 153                 break;
 154             case BufferedImage.TYPE_BYTE_GRAY:
 155                 sData = createDataBC(bufImg, SurfaceType.ByteGray, 0);
 156                 break;
 157             case BufferedImage.TYPE_USHORT_GRAY:
 158                 sData = createDataSC(bufImg, SurfaceType.UshortGray, null);
 159                 break;
 160             case BufferedImage.TYPE_BYTE_BINARY:
 161             case BufferedImage.TYPE_CUSTOM:
 162             default: {
 163                 Raster raster = bufImg.getRaster();
 164 
 165                 // we try to fit a custom image into one of the predefined BufferedImages (BufferedImage does that
 166                 // first, we further refine it here)
 167                 // we can do that because a pointer in C is a pointer (pixel pointer not dependent on DataBuffer type)
 168                 SampleModel sm = bufImg.getSampleModel();
 169                 SurfaceType sType = SurfaceType.Custom;
 170                 int transferType = cm.getTransferType();
 171                 int pixelSize = cm.getPixelSize();
 172                 int numOfComponents = cm.getNumColorComponents();
 173                 if ((numOfComponents == 3) && (cm instanceof ComponentColorModel) && (sm instanceof PixelInterleavedSampleModel)) {
 174                     int sizes[] = cm.getComponentSize();
 175                     boolean validsizes = (sizes[0] == 8) && (sizes[1] == 8) && (sizes[2] == 8);
 176                     int[] offs = ((ComponentSampleModel) sm).getBandOffsets();
 177                     int numBands = raster.getNumBands();
 178                     boolean bigendian = (offs[0] == numBands - 3) && (offs[1] == numBands - 2) && (offs[2] == numBands - 1);
 179                     boolean littleendian = (offs[0] == numBands - 1) && (offs[1] == numBands - 2) && (offs[2] == numBands - 3);
 180 
 181                     if ((pixelSize == 32) && (transferType == DataBuffer.TYPE_INT)) {
 182                         if (validsizes && bigendian && cm.hasAlpha() && cm.isAlphaPremultiplied() && sizes[3] == 8) {
 183                             try {
 184                                 sData = createDataIC(bufImg, sType, BufferedImage.TYPE_INT_ARGB_PRE);
 185                             } catch (ClassCastException e) {
 186                                 sData = null;
 187                             }
 188                         } else if (validsizes && bigendian && cm.hasAlpha() && sizes[3] == 8) {
 189                             try {
 190                                 sData = createDataIC(bufImg, sType, BufferedImage.TYPE_INT_ARGB);
 191                             } catch (ClassCastException e) {
 192                                 sData = null;
 193                             }
 194                         } else if (validsizes && littleendian && cm.hasAlpha() && cm.isAlphaPremultiplied() && sizes[3] == 8) {
 195                             try {
 196                                 sData = createDataIC(bufImg, sType, BufferedImage.TYPE_4BYTE_ABGR_PRE);
 197                             } catch (ClassCastException e) {
 198                                 sData = null;
 199                             }
 200                         } else if (validsizes && littleendian && cm.hasAlpha() && sizes[3] == 8) {
 201                             try {
 202                                 sData = createDataIC(bufImg, sType, BufferedImage.TYPE_4BYTE_ABGR);
 203                             } catch (ClassCastException e) {
 204                                 sData = null;
 205                             }
 206                         } else if (validsizes && bigendian) {
 207                             try {
 208                                 sData = createDataIC(bufImg, sType, BufferedImage.TYPE_INT_RGB);
 209                             } catch (ClassCastException e) {
 210                                 sData = null;
 211                             }
 212                         }
 213                     } else if ((pixelSize == 32) && (transferType == DataBuffer.TYPE_BYTE)) {
 214                         if (validsizes && bigendian && cm.hasAlpha() && cm.isAlphaPremultiplied() && sizes[3] == 8) {
 215                             try {
 216                                 sData = createDataBC(bufImg, sType, 3, BufferedImage.TYPE_INT_ARGB_PRE);
 217                             } catch (ClassCastException e) {
 218                                 sData = null;
 219                             }
 220                         }
 221                         if (validsizes && bigendian && cm.hasAlpha() && sizes[3] == 8) {
 222                             try {
 223                                 sData = createDataBC(bufImg, sType, 3, BufferedImage.TYPE_INT_ARGB);
 224                             } catch (ClassCastException e) {
 225                                 sData = null;
 226                             }
 227                         } else if (validsizes && littleendian && cm.hasAlpha() && cm.isAlphaPremultiplied() && sizes[3] == 8) {
 228                             try {
 229                                 sData = createDataBC(bufImg, sType, 3, BufferedImage.TYPE_4BYTE_ABGR_PRE);
 230                             } catch (ClassCastException e) {
 231                                 sData = null;
 232                             }
 233                         } else if (validsizes && littleendian && cm.hasAlpha() && sizes[3] == 8) {
 234                             try {
 235                                 sData = createDataBC(bufImg, sType, 3, BufferedImage.TYPE_4BYTE_ABGR);
 236                             } catch (ClassCastException e) {
 237                                 sData = null;
 238                             }
 239                         } else if (validsizes && littleendian) {
 240                             try {
 241                                 sData = createDataBC(bufImg, sType, 3, BufferedImage.TYPE_INT_BGR);
 242                             } catch (ClassCastException e) {
 243                                 sData = null;
 244                             }
 245                         } else if (validsizes && bigendian) {
 246                             try {
 247                                 sData = createDataBC(bufImg, sType, 3, BufferedImage.TYPE_INT_RGB);
 248                             } catch (ClassCastException e) {
 249                                 sData = null;
 250                             }
 251                         }
 252                     } else if ((pixelSize == 24) && (transferType == DataBuffer.TYPE_INT)) {
 253                         if (validsizes && bigendian) {
 254                             try {
 255                                 sData = createDataIC(bufImg, sType, BufferedImage.TYPE_INT_RGB);
 256                             } catch (ClassCastException e) {
 257                                 sData = null;
 258                             }
 259                         } else if (validsizes && littleendian) {
 260                             try {
 261                                 sData = createDataIC(bufImg, sType, BufferedImage.TYPE_INT_BGR);
 262                             } catch (ClassCastException e) {
 263                                 sData = null;
 264                             }
 265                         }
 266                     } else if ((pixelSize == 24) && (transferType == DataBuffer.TYPE_BYTE)) {
 267                         if (validsizes && bigendian) {
 268                             try {
 269                                 sData = createDataBC(bufImg, sType, 0, TYPE_3BYTE_RGB);
 270                             } catch (ClassCastException e) {
 271                                 sData = null;
 272                             }
 273                         } else if (validsizes && littleendian) {
 274                             try {
 275                                 sData = createDataBC(bufImg, sType, 0, BufferedImage.TYPE_3BYTE_BGR);
 276                             } catch (ClassCastException e) {
 277                                 sData = null;
 278                             }
 279                         }
 280                     } else if ((pixelSize == 16) && (transferType == DataBuffer.TYPE_USHORT)) {
 281                         validsizes = (sizes[0] == 5) && (sizes[1] == 6) && (sizes[2] == 5);
 282                         if (validsizes && bigendian) {
 283                             try {
 284                                 sData = createDataSC(bufImg, sType, null, BufferedImage.TYPE_USHORT_565_RGB);
 285                             } catch (ClassCastException e) {
 286                                 sData = null;
 287                             }
 288                         }
 289                     } else if ((pixelSize == 16) && (transferType == DataBuffer.TYPE_BYTE)) {
 290                         validsizes = (sizes[0] == 5) && (sizes[1] == 6) && (sizes[2] == 5);
 291                         if (validsizes && bigendian) {
 292                             try {
 293                                 sData = createDataBC(bufImg, sType, 1, BufferedImage.TYPE_USHORT_565_RGB);
 294                             } catch (ClassCastException e) {
 295                                 sData = null;
 296                             }
 297                         }
 298                     } else if ((pixelSize == 15) && (transferType == DataBuffer.TYPE_USHORT)) {
 299                         validsizes = (sizes[0] == 5) && (sizes[1] == 5) && (sizes[2] == 5);
 300                         if (validsizes && bigendian) {
 301                             try {
 302                                 sData = createDataSC(bufImg, sType, null, BufferedImage.TYPE_USHORT_555_RGB);
 303                             } catch (ClassCastException e) {
 304                                 sData = null;
 305                             }
 306                         }
 307                     } else if ((pixelSize == 15) && (transferType == DataBuffer.TYPE_BYTE)) {
 308                         validsizes = (sizes[0] == 5) && (sizes[1] == 5) && (sizes[2] == 5);
 309                         if (validsizes && bigendian) {
 310                             try {
 311                                 sData = createDataBC(bufImg, sType, 1, BufferedImage.TYPE_USHORT_555_RGB);
 312                             } catch (ClassCastException e) {
 313                                 sData = null;
 314                             }
 315                         }
 316                     }
 317                 }
 318             }
 319                 break;
 320         }
 321 
 322         // we failed to match
 323         if (sData == null) {
 324             sData = new OSXOffScreenSurfaceData(bufImg, SurfaceType.Custom);
 325             OSXOffScreenSurfaceData offsd = (OSXOffScreenSurfaceData) sData;
 326 
 327             // 2004_03_26 cmc: We used to use createCompatibleImage here. Now that createCompatibleImage returns
 328             // an INT_ARGB_PRE instead of an NIO-based image, we need to explicitly create an NIO-based image.
 329             IntegerNIORaster backupRaster = (IntegerNIORaster) IntegerNIORaster.createNIORaster(bufImg.getWidth(), bufImg.getHeight(), dcmBackup.getMasks(), null);
 330             offsd.bimBackup = new BufferedImage(dcmBackup, backupRaster, dcmBackup.isAlphaPremultiplied(), null);
 331 
 332             // the trick that makes it work - assign the raster from backup to the surface data of the original image
 333             offsd.initCustomRaster(backupRaster.getBuffer(),
 334                                     backupRaster.getWidth(),
 335                                     backupRaster.getHeight(),
 336                                     offsd.fGraphicsStates,
 337                                     offsd.fGraphicsStatesObject,
 338                                     offsd.fImageInfo);
 339 
 340             //offsd.checkIfLazyPixelConversionDisabled();
 341             offsd.fImageInfoInt.put(kImageStolenIndex, 1);
 342         }
 343 
 344         return (OSXOffScreenSurfaceData) sData;
 345     }
 346 
 347     private static SurfaceData createDataIC(BufferedImage bImg, SurfaceType sType, int iType) {
 348         OSXOffScreenSurfaceData offsd = new OSXOffScreenSurfaceData(bImg, sType);
 349 
 350         IntegerComponentRaster icRaster = (IntegerComponentRaster) bImg.getRaster();
 351         offsd.initRaster(icRaster.getDataStorage(),
 352                             icRaster.getDataOffset(0) * 4,
 353                             icRaster.getWidth(),
 354                             icRaster.getHeight(),
 355                             icRaster.getPixelStride() * 4,
 356                             icRaster.getScanlineStride() * 4,
 357                             null,
 358                             iType,
 359                             offsd.fGraphicsStates,
 360                             offsd.fGraphicsStatesObject,
 361                             offsd.fImageInfo);
 362 
 363        // offsd.checkIfLazyPixelConversionDisabled();
 364         offsd.fImageInfoInt.put(kImageStolenIndex, 1);
 365         return offsd;
 366     }
 367 
 368     public static SurfaceData createDataIC(BufferedImage bImg, SurfaceType sType) {
 369         return createDataIC(bImg, sType, bImg.getType());
 370     }
 371 
 372     private static SurfaceData createDataSC(BufferedImage bImg, SurfaceType sType, IndexColorModel icm, int iType) {
 373         OSXOffScreenSurfaceData offsd = new OSXOffScreenSurfaceData(bImg, sType);
 374 
 375         ShortComponentRaster scRaster = (ShortComponentRaster) bImg.getRaster();
 376         offsd.initRaster(scRaster.getDataStorage(),
 377                             scRaster.getDataOffset(0) * 2,
 378                             scRaster.getWidth(),
 379                             scRaster.getHeight(),
 380                             scRaster.getPixelStride() * 2,
 381                             scRaster.getScanlineStride() * 2,
 382                             icm,
 383                             iType,
 384                             offsd.fGraphicsStates,
 385                             offsd.fGraphicsStatesObject,
 386                             offsd.fImageInfo);
 387 
 388         //offsd.checkIfLazyPixelConversionDisabled();
 389         offsd.fImageInfoInt.put(kImageStolenIndex, 1);
 390         return offsd;
 391     }
 392 
 393     public static SurfaceData createDataSC(BufferedImage bImg, SurfaceType sType, IndexColorModel icm) {
 394         return createDataSC(bImg, sType, icm, bImg.getType());
 395     }
 396 
 397     private static SurfaceData createDataBC(BufferedImage bImg, SurfaceType sType, int primaryBank, int iType) {
 398         OSXOffScreenSurfaceData offsd = new OSXOffScreenSurfaceData(bImg, sType);
 399 
 400         ByteComponentRaster bcRaster = (ByteComponentRaster) bImg.getRaster();
 401         ColorModel cm = bImg.getColorModel();
 402         IndexColorModel icm = ((cm instanceof IndexColorModel) ? (IndexColorModel) cm : null);
 403         offsd.initRaster(bcRaster.getDataStorage(),
 404                             bcRaster.getDataOffset(primaryBank),
 405                             bcRaster.getWidth(),
 406                             bcRaster.getHeight(),
 407                             bcRaster.getPixelStride(),
 408                             bcRaster.getScanlineStride(),
 409                             icm,
 410                             iType,
 411                             offsd.fGraphicsStates,
 412                             offsd.fGraphicsStatesObject,
 413                             offsd.fImageInfo);
 414 
 415         offsd.fImageInfoInt.put(kImageStolenIndex, 1);
 416 
 417         return offsd;
 418     }
 419 
 420     public static SurfaceData createDataBC(BufferedImage bImg, SurfaceType sType, int primaryBank) {
 421         return createDataBC(bImg, sType, primaryBank, bImg.getType());
 422     }
 423 
 424     private static SurfaceData createDataBP(BufferedImage bImg, SurfaceType sType, int iType) {
 425         OSXOffScreenSurfaceData offsd = new OSXOffScreenSurfaceData(bImg, sType);
 426 
 427         BytePackedRaster bpRaster = (BytePackedRaster) bImg.getRaster();
 428         ColorModel cm = bImg.getColorModel();
 429         IndexColorModel icm = ((cm instanceof IndexColorModel) ? (IndexColorModel) cm : null);
 430         offsd.initRaster(bpRaster.getDataStorage(),
 431                             bpRaster.getDataBitOffset(), // in bits, NOT bytes! (needs special attention in native
 432                                                          // code!)
 433                 bpRaster.getWidth(),
 434                             bpRaster.getHeight(),
 435                             bpRaster.getPixelBitStride(),
 436                             bpRaster.getScanlineStride() * 8,
 437                             icm,
 438                             iType,
 439                             offsd.fGraphicsStates,
 440                             offsd.fGraphicsStatesObject,
 441                             offsd.fImageInfo);
 442 
 443         //offsd.checkIfLazyPixelConversionDisabled();
 444         offsd.fImageInfoInt.put(kImageStolenIndex, 1);
 445         return offsd;
 446     }
 447 
 448     protected native void initRaster(Object theArray, int offset, int width, int height, int pixStr, int scanStr, IndexColorModel icm, int type, ByteBuffer graphicsStates, Object graphicsStatesObjects, ByteBuffer imageInfo);
 449 
 450     protected native void initCustomRaster(IntBuffer buffer, int width, int height, ByteBuffer graphicsStates, Object graphicsStatesObjects, ByteBuffer imageInfo);
 451 
 452     public Object getLockObject() {
 453         return this.lock;
 454     }
 455 
 456     // Makes the constructor package private instead of public.
 457     OSXOffScreenSurfaceData(BufferedImage bufImg, SurfaceType sType) {
 458         super(sType, bufImg.getColorModel());
 459         setBounds(0, 0, bufImg.getWidth(), bufImg.getHeight());
 460 
 461         this.bim = bufImg;
 462 
 463         this.fImageInfo = ByteBuffer.allocateDirect(4 * kSizeOfParameters);
 464         this.fImageInfo.order(ByteOrder.nativeOrder());
 465         this.fImageInfoInt = this.fImageInfo.asIntBuffer();
 466 
 467         this.fImageInfoInt.put(kNeedToSyncFromJavaPixelsIndex, 1); // need to sync from Java the very first time
 468         this.fImageInfoInt.put(kNativePixelsChangedIndex, 0);
 469         this.fImageInfoInt.put(kImageStolenIndex, 0);
 470 
 471         this.lock = new Object();
 472     }
 473 
 474     /**
 475      * Performs a copyArea within this surface.
 476      */
 477     public boolean copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, int dx, int dy) {
 478         // <rdar://problem/4488745> For the Sun2D renderer we should rely on the implementation of the super class.
 479         // BufImageSurfaceData.java doesn't have an implementation of copyArea() and relies on the super class.
 480 
 481         if (sg2d.transformState > SunGraphics2D.TRANSFORM_ANY_TRANSLATE) {
 482             return false;
 483         }
 484 
 485         // reset the clip (this is how it works on windows)
 486         // we actually can handle a case with any clips but windows ignores the light clip
 487         Shape clip = sg2d.getClip();
 488         sg2d.setClip(getBounds());
 489 
 490         // clip copyArea
 491         Rectangle clippedCopyAreaRect = clipCopyArea(sg2d, x, y, w, h, dx, dy);
 492         if (clippedCopyAreaRect == null) {
 493             // clipped out
 494             return true;
 495         }
 496 
 497         // the rectangle returned from clipCopyArea() is in the coordinate space
 498         // of the surface (image)
 499         x = clippedCopyAreaRect.x;
 500         y = clippedCopyAreaRect.y;
 501         w = clippedCopyAreaRect.width;
 502         h = clippedCopyAreaRect.height;
 503 
 504         // copy (dst coordinates are in the coord space of the graphics2d, and
 505         // src coordinates are in the coordinate space of the image)
 506         // sg2d.drawImage expects the destination rect to be in the coord space
 507         // of the graphics2d. <rdar://3746194> (vm)
 508         // we need to substract the transX and transY to move it
 509         // to the coordinate space of the graphics2d.
 510         int dstX = x + dx - sg2d.transX;
 511         int dstY = x + dx - sg2d.transY;
 512         sg2d.drawImage(this.bim, dstX, dstY, dstX + w, dstY + h,
 513                        x, y, x + w, y + h, null);
 514 
 515         // restore the clip
 516         sg2d.setClip(clip);
 517 
 518         return true;
 519     }
 520 
 521     /**
 522      * Performs a copyarea from this surface to a buffered image. If null is passed in for the image a new image will be
 523      * created.
 524      *
 525      * Only used by compositor code (private API)
 526      */
 527     public BufferedImage copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, BufferedImage dstImage) {
 528         // create the destination image if needed
 529         if (dstImage == null) {
 530             dstImage = getDeviceConfiguration().createCompatibleImage(w, h);
 531         }
 532 
 533         // copy
 534         Graphics g = dstImage.createGraphics();
 535         g.drawImage(this.bim, 0, 0, w, h, x, y, x + w, y + h, null);
 536         g.dispose();
 537 
 538         return dstImage;
 539     }
 540 
 541     public boolean xorSurfacePixels(SunGraphics2D sg2d, BufferedImage srcPixels, int x, int y, int w, int h, int colorXOR) {
 542 
 543         int type = this.bim.getType();
 544 
 545         if ((type == BufferedImage.TYPE_INT_ARGB_PRE) || (type == BufferedImage.TYPE_INT_ARGB) || (type == BufferedImage.TYPE_INT_RGB)) { return xorSurfacePixels(createData(srcPixels), colorXOR, x, y, w, h); }
 546 
 547         return false;
 548     }
 549 
 550     native boolean xorSurfacePixels(SurfaceData src, int colorXOR, int x, int y, int w, int h);
 551 
 552     public void clearRect(BufferedImage bim, int w, int h) {
 553         OSXOffScreenSurfaceData offsd = (OSXOffScreenSurfaceData) (OSXOffScreenSurfaceData.createData(bim));
 554         // offsd.clear();
 555         if (offsd.clearSurfacePixels(w, h) == false) {
 556             Graphics2D g = bim.createGraphics();
 557             g.setComposite(AlphaComposite.Clear);
 558             g.fillRect(0, 0, w, h);
 559             g.dispose();
 560         }
 561     }
 562 
 563     native boolean clearSurfacePixels(int w, int h);
 564 
 565     // 04/06/04 cmc: radr://3612381 Graphics.drawImage ignores bgcolor parameter.
 566     // getCopyWithBgColor returns a new version of an image, drawn with a background
 567     // color. Called by blitImage in OSXSurfaceData.java.
 568     BufferedImage copyWithBgColor_cache = null;
 569 
 570     public SurfaceData getCopyWithBgColor(Color bgColor) {
 571         int bimW = this.bim.getWidth();
 572         int bimH = this.bim.getHeight();
 573 
 574         if ((this.copyWithBgColor_cache == null)
 575                 || (this.copyWithBgColor_cache.getWidth() < bimW) || (this.copyWithBgColor_cache.getHeight() < bimH)) {
 576             GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
 577             this.copyWithBgColor_cache = gc.createCompatibleImage(bimW, bimH);
 578         }
 579 
 580         Graphics g2 = this.copyWithBgColor_cache.createGraphics();
 581         g2.setColor(bgColor);
 582         g2.fillRect(0, 0, bimW, bimH);
 583         g2.drawImage(this.bim, 0, 0, bimW, bimH, null);
 584         g2.dispose();
 585 
 586         return getSurfaceData(this.copyWithBgColor_cache);
 587     }
 588 
 589     /**
 590      * Invoked before the raster's contents are to be read (via one of the modifier methods in Raster such as
 591      * getPixel())
 592      */
 593     public void rasterRead() {
 594         if (fImageInfoInt.get(kNativePixelsChangedIndex) == 1) {
 595             syncToJavaPixels();
 596         }
 597     }
 598 
 599     /**
 600      * Invoked before the raster's contents are to be written to (via one of the modifier methods in Raster such as
 601      * setPixel())
 602      */
 603     public void rasterWrite() {
 604         if (fImageInfoInt.get(kNativePixelsChangedIndex) == 1) {
 605             syncToJavaPixels();
 606         }
 607 
 608         fImageInfoInt.put(kNeedToSyncFromJavaPixelsIndex, 1); // the pixels will change
 609     }
 610 
 611 //    /**
 612 //     * Invoked when the raster's contents will be taken (via the Raster.getDataBuffer() method)
 613 //     */
 614 //    public void rasterStolen() {
 615 //        fImageInfoInt.put(kImageStolenIndex, 1); // this means we must convert between Java and native pixels every
 616 //                                                 // single primitive! (very expensive)
 617 //        if (fImageInfoInt.get(kNativePixelsChangedIndex) == 1) {
 618 //            syncToJavaPixels();
 619 //        }
 620 //
 621 //        // we know the pixels have been stolen, no need to listen for changes any more
 622 ////        if (this.bufImgSunRaster != null) {
 623 ////            this.bufImgSunRaster.setRasterListener(null);
 624 ////        }
 625 //    }
 626 
 627     private native void syncToJavaPixels();
 628 
 629     // we need to refer to rasters often, so cache them
 630     void cacheRasters(BufferedImage bim) {
 631         this.bufImgRaster = bim.getRaster();
 632         if (this.bufImgRaster instanceof SunWritableRaster) {
 633             this.bufImgSunRaster = (SunWritableRaster) this.bufImgRaster;
 634         }
 635     }
 636 
 637 //    void setRasterListener() {
 638 //        if (this.bufImgSunRaster != null) {
 639 //            this.bufImgSunRaster.setRasterListener(this);
 640 //
 641 //            Raster parentRaster = this.bufImgSunRaster.getParent();
 642 //            if (parentRaster != null) {
 643 //                if (parentRaster instanceof SunWritableRaster) {
 644 //                    // mark subimages stolen to turn off lazy pixel conversion (gznote: can we do better here?)
 645 //                    ((SunWritableRaster) parentRaster).notifyStolen();
 646 //                }
 647 //                rasterStolen();
 648 //            }
 649 //        } else {
 650 //            // it's a custom image (non-natively supported) and we can not set a raster listener
 651 //            // so mark the image as stolen - this will turn off LazyPixelConversion optimization (slow, but correct)
 652 //            rasterStolen();
 653 //        }
 654 //    }
 655 }