1 /*
2  * Copyright (c) 2011, 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.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 {
initIDs()38     private static native void initIDs();
39 
40     static {
initIDs()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 
getSurfaceData(BufferedImage bufImg)68     public static native SurfaceData getSurfaceData(BufferedImage bufImg);
69 
setSurfaceData(BufferedImage bufImg, SurfaceData sData)70     protected static native void setSurfaceData(BufferedImage bufImg, SurfaceData sData);
71 
createData(BufferedImage bufImg)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 
createData(Raster ras, ColorModel cm)94     public static SurfaceData createData(Raster ras, ColorModel cm) {
95         throw new InternalError("SurfaceData not implemented for Raster/CM");
96     }
97 
createNewSurface(BufferedImage bufImg)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 
createDataIC(BufferedImage bImg, SurfaceType sType, int iType)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 
createDataIC(BufferedImage bImg, SurfaceType sType)368     public static SurfaceData createDataIC(BufferedImage bImg, SurfaceType sType) {
369         return createDataIC(bImg, sType, bImg.getType());
370     }
371 
createDataSC(BufferedImage bImg, SurfaceType sType, IndexColorModel icm, int iType)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 
createDataSC(BufferedImage bImg, SurfaceType sType, IndexColorModel icm)393     public static SurfaceData createDataSC(BufferedImage bImg, SurfaceType sType, IndexColorModel icm) {
394         return createDataSC(bImg, sType, icm, bImg.getType());
395     }
396 
createDataBC(BufferedImage bImg, SurfaceType sType, int primaryBank, int iType)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 
createDataBC(BufferedImage bImg, SurfaceType sType, int primaryBank)420     public static SurfaceData createDataBC(BufferedImage bImg, SurfaceType sType, int primaryBank) {
421         return createDataBC(bImg, sType, primaryBank, bImg.getType());
422     }
423 
createDataBP(BufferedImage bImg, SurfaceType sType, int iType)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 
initRaster(Object theArray, int offset, int width, int height, int pixStr, int scanStr, IndexColorModel icm, int type, ByteBuffer graphicsStates, Object graphicsStatesObjects, ByteBuffer imageInfo)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 
initCustomRaster(IntBuffer buffer, int width, int height, ByteBuffer graphicsStates, Object graphicsStatesObjects, ByteBuffer imageInfo)450     protected native void initCustomRaster(IntBuffer buffer, int width, int height, ByteBuffer graphicsStates, Object graphicsStatesObjects, ByteBuffer imageInfo);
451 
getLockObject()452     public Object getLockObject() {
453         return this.lock;
454     }
455 
456     // Makes the constructor package private instead of public.
OSXOffScreenSurfaceData(BufferedImage bufImg, SurfaceType sType)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      */
copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, int dx, int dy)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_TRANSLATESCALE) {
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 = y + dy - 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      */
copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, BufferedImage dstImage)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 
xorSurfacePixels(SunGraphics2D sg2d, BufferedImage srcPixels, int x, int y, int w, int h, int colorXOR)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 
xorSurfacePixels(SurfaceData src, int colorXOR, int x, int y, int w, int h)550     native boolean xorSurfacePixels(SurfaceData src, int colorXOR, int x, int y, int w, int h);
551 
clearRect(BufferedImage bim, int w, int h)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 
clearSurfacePixels(int w, int h)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 
getCopyWithBgColor(Color bgColor)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      */
rasterRead()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      */
rasterWrite()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 
syncFromCustom()611     private void syncFromCustom() {
612 
613     }
614 
syncToCustom()615     private void syncToCustom() {
616 
617     }
618 //    /**
619 //     * Invoked when the raster's contents will be taken (via the Raster.getDataBuffer() method)
620 //     */
621 //    public void rasterStolen() {
622 //        fImageInfoInt.put(kImageStolenIndex, 1); // this means we must convert between Java and native pixels every
623 //                                                 // single primitive! (very expensive)
624 //        if (fImageInfoInt.get(kNativePixelsChangedIndex) == 1) {
625 //            syncToJavaPixels();
626 //        }
627 //
628 //        // we know the pixels have been stolen, no need to listen for changes any more
629 ////        if (this.bufImgSunRaster != null) {
630 ////            this.bufImgSunRaster.setRasterListener(null);
631 ////        }
632 //    }
633 
syncToJavaPixels()634     private native void syncToJavaPixels();
635 
636     // we need to refer to rasters often, so cache them
cacheRasters(BufferedImage bim)637     void cacheRasters(BufferedImage bim) {
638         this.bufImgRaster = bim.getRaster();
639         if (this.bufImgRaster instanceof SunWritableRaster) {
640             this.bufImgSunRaster = (SunWritableRaster) this.bufImgRaster;
641         }
642     }
643 
644 //    void setRasterListener() {
645 //        if (this.bufImgSunRaster != null) {
646 //            this.bufImgSunRaster.setRasterListener(this);
647 //
648 //            Raster parentRaster = this.bufImgSunRaster.getParent();
649 //            if (parentRaster != null) {
650 //                if (parentRaster instanceof SunWritableRaster) {
651 //                    // mark subimages stolen to turn off lazy pixel conversion (gznote: can we do better here?)
652 //                    ((SunWritableRaster) parentRaster).notifyStolen();
653 //                }
654 //                rasterStolen();
655 //            }
656 //        } else {
657 //            // it's a custom image (non-natively supported) and we can not set a raster listener
658 //            // so mark the image as stolen - this will turn off LazyPixelConversion optimization (slow, but correct)
659 //            rasterStolen();
660 //        }
661 //    }
662 }
663