1 /*
2  * Copyright (c) 2011, 2017, 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         int offsetX = 0;
482         int offsetY = 0;
483         if (sg2d.transformState == SunGraphics2D.TRANSFORM_ANY_TRANSLATE ||
484                     sg2d.transformState == SunGraphics2D.TRANSFORM_INT_TRANSLATE) {
485             offsetX = (int) sg2d.transform.getTranslateX();
486             offsetY = (int) sg2d.transform.getTranslateY();
487         } else if (sg2d.transformState != SunGraphics2D.TRANSFORM_ISIDENT) { return false; }
488 
489         // reset the clip (this is how it works on windows)
490         // we actually can handle a case with any clips but windows ignores the light clip
491         Shape clip = sg2d.getClip();
492         sg2d.setClip(getBounds());
493 
494         // clip copyArea
495         Rectangle clippedCopyAreaRect = clipCopyArea(sg2d, x, y, w, h, dx, dy);
496         if (clippedCopyAreaRect == null) {
497             // clipped out
498             return true;
499         }
500 
501         // the rectangle returned from clipCopyArea() is in the coordinate space of the surface (image)
502         // we need to substract the offsetX and offsetY to move it to the coordinate space of the graphics2d.
503         // sg2d.drawImage expects the destination rect to be in the coord space of the graphics2d. <rdar://3746194>
504         // (vm)
505         x = clippedCopyAreaRect.x - offsetX;
506         y = clippedCopyAreaRect.y - offsetY;
507         w = clippedCopyAreaRect.width;
508         h = clippedCopyAreaRect.height;
509 
510         // copy (dst coordinates are in the coord space of the graphics2d, and src coordinates are
511         // in the coordinate space of the image)
512         sg2d.drawImage(this.bim, x + dx, y + dy, x + dx + w, y + dy + h, x + offsetX, y + offsetY, x + w + offsetX, y + h + offsetY, null);
513 
514         // restore the clip
515         sg2d.setClip(clip);
516 
517         return true;
518     }
519 
520     /**
521      * Performs a copyarea from this surface to a buffered image. If null is passed in for the image a new image will be
522      * created.
523      *
524      * Only used by compositor code (private API)
525      */
copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, BufferedImage dstImage)526     public BufferedImage copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, BufferedImage dstImage) {
527         // create the destination image if needed
528         if (dstImage == null) {
529             dstImage = getDeviceConfiguration().createCompatibleImage(w, h);
530         }
531 
532         // copy
533         Graphics g = dstImage.createGraphics();
534         g.drawImage(this.bim, 0, 0, w, h, x, y, x + w, y + h, null);
535         g.dispose();
536 
537         return dstImage;
538     }
539 
xorSurfacePixels(SunGraphics2D sg2d, BufferedImage srcPixels, int x, int y, int w, int h, int colorXOR)540     public boolean xorSurfacePixels(SunGraphics2D sg2d, BufferedImage srcPixels, int x, int y, int w, int h, int colorXOR) {
541 
542         int type = this.bim.getType();
543 
544         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); }
545 
546         return false;
547     }
548 
xorSurfacePixels(SurfaceData src, int colorXOR, int x, int y, int w, int h)549     native boolean xorSurfacePixels(SurfaceData src, int colorXOR, int x, int y, int w, int h);
550 
clearRect(BufferedImage bim, int w, int h)551     public void clearRect(BufferedImage bim, int w, int h) {
552         OSXOffScreenSurfaceData offsd = (OSXOffScreenSurfaceData) (OSXOffScreenSurfaceData.createData(bim));
553         // offsd.clear();
554         if (offsd.clearSurfacePixels(w, h) == false) {
555             Graphics2D g = bim.createGraphics();
556             g.setComposite(AlphaComposite.Clear);
557             g.fillRect(0, 0, w, h);
558             g.dispose();
559         }
560     }
561 
clearSurfacePixels(int w, int h)562     native boolean clearSurfacePixels(int w, int h);
563 
564     // 04/06/04 cmc: radr://3612381 Graphics.drawImage ignores bgcolor parameter.
565     // getCopyWithBgColor returns a new version of an image, drawn with a background
566     // color. Called by blitImage in OSXSurfaceData.java.
567     BufferedImage copyWithBgColor_cache = null;
568 
getCopyWithBgColor(Color bgColor)569     public SurfaceData getCopyWithBgColor(Color bgColor) {
570         int bimW = this.bim.getWidth();
571         int bimH = this.bim.getHeight();
572 
573         if ((this.copyWithBgColor_cache == null)
574                 || (this.copyWithBgColor_cache.getWidth() < bimW) || (this.copyWithBgColor_cache.getHeight() < bimH)) {
575             GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
576             this.copyWithBgColor_cache = gc.createCompatibleImage(bimW, bimH);
577         }
578 
579         Graphics g2 = this.copyWithBgColor_cache.createGraphics();
580         g2.setColor(bgColor);
581         g2.fillRect(0, 0, bimW, bimH);
582         g2.drawImage(this.bim, 0, 0, bimW, bimH, null);
583         g2.dispose();
584 
585         return getSurfaceData(this.copyWithBgColor_cache);
586     }
587 
588     /**
589      * Invoked before the raster's contents are to be read (via one of the modifier methods in Raster such as
590      * getPixel())
591      */
rasterRead()592     public void rasterRead() {
593         if (fImageInfoInt.get(kNativePixelsChangedIndex) == 1) {
594             syncToJavaPixels();
595         }
596     }
597 
598     /**
599      * Invoked before the raster's contents are to be written to (via one of the modifier methods in Raster such as
600      * setPixel())
601      */
rasterWrite()602     public void rasterWrite() {
603         if (fImageInfoInt.get(kNativePixelsChangedIndex) == 1) {
604             syncToJavaPixels();
605         }
606 
607         fImageInfoInt.put(kNeedToSyncFromJavaPixelsIndex, 1); // the pixels will change
608     }
609 
syncFromCustom()610     private void syncFromCustom() {
611 
612     }
613 
syncToCustom()614     private void syncToCustom() {
615 
616     }
617 //    /**
618 //     * Invoked when the raster's contents will be taken (via the Raster.getDataBuffer() method)
619 //     */
620 //    public void rasterStolen() {
621 //        fImageInfoInt.put(kImageStolenIndex, 1); // this means we must convert between Java and native pixels every
622 //                                                 // single primitive! (very expensive)
623 //        if (fImageInfoInt.get(kNativePixelsChangedIndex) == 1) {
624 //            syncToJavaPixels();
625 //        }
626 //
627 //        // we know the pixels have been stolen, no need to listen for changes any more
628 ////        if (this.bufImgSunRaster != null) {
629 ////            this.bufImgSunRaster.setRasterListener(null);
630 ////        }
631 //    }
632 
syncToJavaPixels()633     private native void syncToJavaPixels();
634 
635     // we need to refer to rasters often, so cache them
cacheRasters(BufferedImage bim)636     void cacheRasters(BufferedImage bim) {
637         this.bufImgRaster = bim.getRaster();
638         if (this.bufImgRaster instanceof SunWritableRaster) {
639             this.bufImgSunRaster = (SunWritableRaster) this.bufImgRaster;
640         }
641     }
642 
643 //    void setRasterListener() {
644 //        if (this.bufImgSunRaster != null) {
645 //            this.bufImgSunRaster.setRasterListener(this);
646 //
647 //            Raster parentRaster = this.bufImgSunRaster.getParent();
648 //            if (parentRaster != null) {
649 //                if (parentRaster instanceof SunWritableRaster) {
650 //                    // mark subimages stolen to turn off lazy pixel conversion (gznote: can we do better here?)
651 //                    ((SunWritableRaster) parentRaster).notifyStolen();
652 //                }
653 //                rasterStolen();
654 //            }
655 //        } else {
656 //            // it's a custom image (non-natively supported) and we can not set a raster listener
657 //            // so mark the image as stolen - this will turn off LazyPixelConversion optimization (slow, but correct)
658 //            rasterStolen();
659 //        }
660 //    }
661 }
662