| /* |
| * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package sun.java2d; |
| |
| import java.awt.*; |
| import java.awt.color.*; |
| import java.awt.image.*; |
| import java.nio.*; |
| |
| import sun.awt.image.*; |
| import sun.java2d.loops.*; |
| |
| public class OSXOffScreenSurfaceData extends OSXSurfaceData // implements RasterListener |
| { |
| private static native void initIDs(); |
| |
| static { |
| initIDs(); |
| } |
| |
| // the image associated with this surface |
| BufferedImage bim; |
| // the image associated with this custom surface |
| BufferedImage bimBackup; |
| // <rdar://problem/4177639> nio based images use ARGB_PRE |
| static DirectColorModel dcmBackup = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000, true, DataBuffer.TYPE_INT); |
| |
| Object lock; |
| |
| // cached rasters for easy access |
| WritableRaster bufImgRaster; |
| SunWritableRaster bufImgSunRaster; |
| |
| // these are extra image types we can handle |
| private static final int TYPE_3BYTE_RGB = BufferedImage.TYPE_BYTE_INDEXED + 1; |
| |
| // these are for callbacks when pixes have been touched |
| protected ByteBuffer fImageInfo; |
| IntBuffer fImageInfoInt; |
| private static final int kNeedToSyncFromJavaPixelsIndex = 0; |
| private static final int kNativePixelsChangedIndex = 1; |
| private static final int kImageStolenIndex = 2; |
| private static final int kSizeOfParameters = kImageStolenIndex + 1; |
| |
| public static native SurfaceData getSurfaceData(BufferedImage bufImg); |
| |
| protected static native void setSurfaceData(BufferedImage bufImg, SurfaceData sData); |
| |
| public static SurfaceData createData(BufferedImage bufImg) { |
| /* |
| * if ((bufImg.getWidth() == 32) && (bufImg.getHeight() == 32)) { Thread.dumpStack(); } |
| */ |
| // This could be called from multiple threads. We need to synchronized on the image so that |
| // we can ensure that only one surface data is created per image. (<rdar://4564873>) |
| // Note: Eventually, we should switch to using the same mechanism (CachingSurfaceManager) that Sun uses |
| // <rdar://4563741> |
| synchronized (bufImg) { |
| SurfaceData sData = getSurfaceData(bufImg); |
| if (sData != null) { return sData; } |
| |
| OSXOffScreenSurfaceData osData = OSXOffScreenSurfaceData.createNewSurface(bufImg); |
| |
| OSXOffScreenSurfaceData.setSurfaceData(bufImg, osData); |
| osData.cacheRasters(bufImg); |
| // osData.setRasterListener(); |
| |
| return osData; |
| } |
| } |
| |
| public static SurfaceData createData(Raster ras, ColorModel cm) { |
| throw new InternalError("SurfaceData not implemented for Raster/CM"); |
| } |
| |
| static OSXOffScreenSurfaceData createNewSurface(BufferedImage bufImg) { |
| SurfaceData sData = null; |
| |
| ColorModel cm = bufImg.getColorModel(); |
| int type = bufImg.getType(); |
| // REMIND: Check the image type and pick an appropriate subclass |
| switch (type) { |
| case BufferedImage.TYPE_INT_BGR: |
| sData = createDataIC(bufImg, SurfaceType.IntBgr); |
| break; |
| case BufferedImage.TYPE_INT_RGB: |
| sData = createDataIC(bufImg, SurfaceType.IntRgb); |
| break; |
| case BufferedImage.TYPE_INT_ARGB: |
| sData = createDataIC(bufImg, SurfaceType.IntArgb); |
| break; |
| case BufferedImage.TYPE_INT_ARGB_PRE: |
| sData = createDataIC(bufImg, SurfaceType.IntArgbPre); |
| break; |
| case BufferedImage.TYPE_3BYTE_BGR: |
| sData = createDataBC(bufImg, SurfaceType.ThreeByteBgr, 2); |
| break; |
| case BufferedImage.TYPE_4BYTE_ABGR: |
| sData = createDataBC(bufImg, SurfaceType.FourByteAbgr, 3); |
| break; |
| case BufferedImage.TYPE_4BYTE_ABGR_PRE: |
| sData = createDataBC(bufImg, SurfaceType.FourByteAbgrPre, 3); |
| break; |
| case BufferedImage.TYPE_USHORT_565_RGB: |
| sData = createDataSC(bufImg, SurfaceType.Ushort565Rgb, null); |
| break; |
| case BufferedImage.TYPE_USHORT_555_RGB: |
| sData = createDataSC(bufImg, SurfaceType.Ushort555Rgb, null); |
| break; |
| case BufferedImage.TYPE_BYTE_INDEXED: { |
| SurfaceType sType; |
| switch (cm.getTransparency()) { |
| case OPAQUE: |
| if (isOpaqueGray((IndexColorModel) cm)) { |
| sType = SurfaceType.Index8Gray; |
| } else { |
| sType = SurfaceType.ByteIndexedOpaque; |
| } |
| break; |
| case BITMASK: |
| sType = SurfaceType.ByteIndexedBm; |
| break; |
| case TRANSLUCENT: |
| sType = SurfaceType.ByteIndexed; |
| break; |
| default: |
| throw new InternalError("Unrecognized transparency"); |
| } |
| sData = createDataBC(bufImg, sType, 0); |
| } |
| break; |
| case BufferedImage.TYPE_BYTE_GRAY: |
| sData = createDataBC(bufImg, SurfaceType.ByteGray, 0); |
| break; |
| case BufferedImage.TYPE_USHORT_GRAY: |
| sData = createDataSC(bufImg, SurfaceType.UshortGray, null); |
| break; |
| case BufferedImage.TYPE_BYTE_BINARY: |
| case BufferedImage.TYPE_CUSTOM: |
| default: { |
| Raster raster = bufImg.getRaster(); |
| |
| // we try to fit a custom image into one of the predefined BufferedImages (BufferedImage does that |
| // first, we further refine it here) |
| // we can do that because a pointer in C is a pointer (pixel pointer not dependent on DataBuffer type) |
| SampleModel sm = bufImg.getSampleModel(); |
| SurfaceType sType = SurfaceType.Custom; |
| int transferType = cm.getTransferType(); |
| int pixelSize = cm.getPixelSize(); |
| int numOfComponents = cm.getNumColorComponents(); |
| if ((numOfComponents == 3) && (cm instanceof ComponentColorModel) && (sm instanceof PixelInterleavedSampleModel)) { |
| int sizes[] = cm.getComponentSize(); |
| boolean validsizes = (sizes[0] == 8) && (sizes[1] == 8) && (sizes[2] == 8); |
| int[] offs = ((ComponentSampleModel) sm).getBandOffsets(); |
| int numBands = raster.getNumBands(); |
| boolean bigendian = (offs[0] == numBands - 3) && (offs[1] == numBands - 2) && (offs[2] == numBands - 1); |
| boolean littleendian = (offs[0] == numBands - 1) && (offs[1] == numBands - 2) && (offs[2] == numBands - 3); |
| |
| if ((pixelSize == 32) && (transferType == DataBuffer.TYPE_INT)) { |
| if (validsizes && bigendian && cm.hasAlpha() && cm.isAlphaPremultiplied() && sizes[3] == 8) { |
| try { |
| sData = createDataIC(bufImg, sType, BufferedImage.TYPE_INT_ARGB_PRE); |
| } catch (ClassCastException e) { |
| sData = null; |
| } |
| } else if (validsizes && bigendian && cm.hasAlpha() && sizes[3] == 8) { |
| try { |
| sData = createDataIC(bufImg, sType, BufferedImage.TYPE_INT_ARGB); |
| } catch (ClassCastException e) { |
| sData = null; |
| } |
| } else if (validsizes && littleendian && cm.hasAlpha() && cm.isAlphaPremultiplied() && sizes[3] == 8) { |
| try { |
| sData = createDataIC(bufImg, sType, BufferedImage.TYPE_4BYTE_ABGR_PRE); |
| } catch (ClassCastException e) { |
| sData = null; |
| } |
| } else if (validsizes && littleendian && cm.hasAlpha() && sizes[3] == 8) { |
| try { |
| sData = createDataIC(bufImg, sType, BufferedImage.TYPE_4BYTE_ABGR); |
| } catch (ClassCastException e) { |
| sData = null; |
| } |
| } else if (validsizes && bigendian) { |
| try { |
| sData = createDataIC(bufImg, sType, BufferedImage.TYPE_INT_RGB); |
| } catch (ClassCastException e) { |
| sData = null; |
| } |
| } |
| } else if ((pixelSize == 32) && (transferType == DataBuffer.TYPE_BYTE)) { |
| if (validsizes && bigendian && cm.hasAlpha() && cm.isAlphaPremultiplied() && sizes[3] == 8) { |
| try { |
| sData = createDataBC(bufImg, sType, 3, BufferedImage.TYPE_INT_ARGB_PRE); |
| } catch (ClassCastException e) { |
| sData = null; |
| } |
| } |
| if (validsizes && bigendian && cm.hasAlpha() && sizes[3] == 8) { |
| try { |
| sData = createDataBC(bufImg, sType, 3, BufferedImage.TYPE_INT_ARGB); |
| } catch (ClassCastException e) { |
| sData = null; |
| } |
| } else if (validsizes && littleendian && cm.hasAlpha() && cm.isAlphaPremultiplied() && sizes[3] == 8) { |
| try { |
| sData = createDataBC(bufImg, sType, 3, BufferedImage.TYPE_4BYTE_ABGR_PRE); |
| } catch (ClassCastException e) { |
| sData = null; |
| } |
| } else if (validsizes && littleendian && cm.hasAlpha() && sizes[3] == 8) { |
| try { |
| sData = createDataBC(bufImg, sType, 3, BufferedImage.TYPE_4BYTE_ABGR); |
| } catch (ClassCastException e) { |
| sData = null; |
| } |
| } else if (validsizes && littleendian) { |
| try { |
| sData = createDataBC(bufImg, sType, 3, BufferedImage.TYPE_INT_BGR); |
| } catch (ClassCastException e) { |
| sData = null; |
| } |
| } else if (validsizes && bigendian) { |
| try { |
| sData = createDataBC(bufImg, sType, 3, BufferedImage.TYPE_INT_RGB); |
| } catch (ClassCastException e) { |
| sData = null; |
| } |
| } |
| } else if ((pixelSize == 24) && (transferType == DataBuffer.TYPE_INT)) { |
| if (validsizes && bigendian) { |
| try { |
| sData = createDataIC(bufImg, sType, BufferedImage.TYPE_INT_RGB); |
| } catch (ClassCastException e) { |
| sData = null; |
| } |
| } else if (validsizes && littleendian) { |
| try { |
| sData = createDataIC(bufImg, sType, BufferedImage.TYPE_INT_BGR); |
| } catch (ClassCastException e) { |
| sData = null; |
| } |
| } |
| } else if ((pixelSize == 24) && (transferType == DataBuffer.TYPE_BYTE)) { |
| if (validsizes && bigendian) { |
| try { |
| sData = createDataBC(bufImg, sType, 0, TYPE_3BYTE_RGB); |
| } catch (ClassCastException e) { |
| sData = null; |
| } |
| } else if (validsizes && littleendian) { |
| try { |
| sData = createDataBC(bufImg, sType, 0, BufferedImage.TYPE_3BYTE_BGR); |
| } catch (ClassCastException e) { |
| sData = null; |
| } |
| } |
| } else if ((pixelSize == 16) && (transferType == DataBuffer.TYPE_USHORT)) { |
| validsizes = (sizes[0] == 5) && (sizes[1] == 6) && (sizes[2] == 5); |
| if (validsizes && bigendian) { |
| try { |
| sData = createDataSC(bufImg, sType, null, BufferedImage.TYPE_USHORT_565_RGB); |
| } catch (ClassCastException e) { |
| sData = null; |
| } |
| } |
| } else if ((pixelSize == 16) && (transferType == DataBuffer.TYPE_BYTE)) { |
| validsizes = (sizes[0] == 5) && (sizes[1] == 6) && (sizes[2] == 5); |
| if (validsizes && bigendian) { |
| try { |
| sData = createDataBC(bufImg, sType, 1, BufferedImage.TYPE_USHORT_565_RGB); |
| } catch (ClassCastException e) { |
| sData = null; |
| } |
| } |
| } else if ((pixelSize == 15) && (transferType == DataBuffer.TYPE_USHORT)) { |
| validsizes = (sizes[0] == 5) && (sizes[1] == 5) && (sizes[2] == 5); |
| if (validsizes && bigendian) { |
| try { |
| sData = createDataSC(bufImg, sType, null, BufferedImage.TYPE_USHORT_555_RGB); |
| } catch (ClassCastException e) { |
| sData = null; |
| } |
| } |
| } else if ((pixelSize == 15) && (transferType == DataBuffer.TYPE_BYTE)) { |
| validsizes = (sizes[0] == 5) && (sizes[1] == 5) && (sizes[2] == 5); |
| if (validsizes && bigendian) { |
| try { |
| sData = createDataBC(bufImg, sType, 1, BufferedImage.TYPE_USHORT_555_RGB); |
| } catch (ClassCastException e) { |
| sData = null; |
| } |
| } |
| } |
| } |
| } |
| break; |
| } |
| |
| // we failed to match |
| if (sData == null) { |
| sData = new OSXOffScreenSurfaceData(bufImg, SurfaceType.Custom); |
| OSXOffScreenSurfaceData offsd = (OSXOffScreenSurfaceData) sData; |
| |
| // 2004_03_26 cmc: We used to use createCompatibleImage here. Now that createCompatibleImage returns |
| // an INT_ARGB_PRE instead of an NIO-based image, we need to explicitly create an NIO-based image. |
| IntegerNIORaster backupRaster = (IntegerNIORaster) IntegerNIORaster.createNIORaster(bufImg.getWidth(), bufImg.getHeight(), dcmBackup.getMasks(), null); |
| offsd.bimBackup = new BufferedImage(dcmBackup, backupRaster, dcmBackup.isAlphaPremultiplied(), null); |
| |
| // the trick that makes it work - assign the raster from backup to the surface data of the original image |
| offsd.initCustomRaster(backupRaster.getBuffer(), |
| backupRaster.getWidth(), |
| backupRaster.getHeight(), |
| offsd.fGraphicsStates, |
| offsd.fGraphicsStatesObject, |
| offsd.fImageInfo); |
| |
| //offsd.checkIfLazyPixelConversionDisabled(); |
| offsd.fImageInfoInt.put(kImageStolenIndex, 1); |
| } |
| |
| return (OSXOffScreenSurfaceData) sData; |
| } |
| |
| private static SurfaceData createDataIC(BufferedImage bImg, SurfaceType sType, int iType) { |
| OSXOffScreenSurfaceData offsd = new OSXOffScreenSurfaceData(bImg, sType); |
| |
| IntegerComponentRaster icRaster = (IntegerComponentRaster) bImg.getRaster(); |
| offsd.initRaster(icRaster.getDataStorage(), |
| icRaster.getDataOffset(0) * 4, |
| icRaster.getWidth(), |
| icRaster.getHeight(), |
| icRaster.getPixelStride() * 4, |
| icRaster.getScanlineStride() * 4, |
| null, |
| iType, |
| offsd.fGraphicsStates, |
| offsd.fGraphicsStatesObject, |
| offsd.fImageInfo); |
| |
| // offsd.checkIfLazyPixelConversionDisabled(); |
| offsd.fImageInfoInt.put(kImageStolenIndex, 1); |
| return offsd; |
| } |
| |
| public static SurfaceData createDataIC(BufferedImage bImg, SurfaceType sType) { |
| return createDataIC(bImg, sType, bImg.getType()); |
| } |
| |
| private static SurfaceData createDataSC(BufferedImage bImg, SurfaceType sType, IndexColorModel icm, int iType) { |
| OSXOffScreenSurfaceData offsd = new OSXOffScreenSurfaceData(bImg, sType); |
| |
| ShortComponentRaster scRaster = (ShortComponentRaster) bImg.getRaster(); |
| offsd.initRaster(scRaster.getDataStorage(), |
| scRaster.getDataOffset(0) * 2, |
| scRaster.getWidth(), |
| scRaster.getHeight(), |
| scRaster.getPixelStride() * 2, |
| scRaster.getScanlineStride() * 2, |
| icm, |
| iType, |
| offsd.fGraphicsStates, |
| offsd.fGraphicsStatesObject, |
| offsd.fImageInfo); |
| |
| //offsd.checkIfLazyPixelConversionDisabled(); |
| offsd.fImageInfoInt.put(kImageStolenIndex, 1); |
| return offsd; |
| } |
| |
| public static SurfaceData createDataSC(BufferedImage bImg, SurfaceType sType, IndexColorModel icm) { |
| return createDataSC(bImg, sType, icm, bImg.getType()); |
| } |
| |
| private static SurfaceData createDataBC(BufferedImage bImg, SurfaceType sType, int primaryBank, int iType) { |
| OSXOffScreenSurfaceData offsd = new OSXOffScreenSurfaceData(bImg, sType); |
| |
| ByteComponentRaster bcRaster = (ByteComponentRaster) bImg.getRaster(); |
| ColorModel cm = bImg.getColorModel(); |
| IndexColorModel icm = ((cm instanceof IndexColorModel) ? (IndexColorModel) cm : null); |
| offsd.initRaster(bcRaster.getDataStorage(), |
| bcRaster.getDataOffset(primaryBank), |
| bcRaster.getWidth(), |
| bcRaster.getHeight(), |
| bcRaster.getPixelStride(), |
| bcRaster.getScanlineStride(), |
| icm, |
| iType, |
| offsd.fGraphicsStates, |
| offsd.fGraphicsStatesObject, |
| offsd.fImageInfo); |
| |
| offsd.fImageInfoInt.put(kImageStolenIndex, 1); |
| |
| return offsd; |
| } |
| |
| public static SurfaceData createDataBC(BufferedImage bImg, SurfaceType sType, int primaryBank) { |
| return createDataBC(bImg, sType, primaryBank, bImg.getType()); |
| } |
| |
| private static SurfaceData createDataBP(BufferedImage bImg, SurfaceType sType, int iType) { |
| OSXOffScreenSurfaceData offsd = new OSXOffScreenSurfaceData(bImg, sType); |
| |
| BytePackedRaster bpRaster = (BytePackedRaster) bImg.getRaster(); |
| ColorModel cm = bImg.getColorModel(); |
| IndexColorModel icm = ((cm instanceof IndexColorModel) ? (IndexColorModel) cm : null); |
| offsd.initRaster(bpRaster.getDataStorage(), |
| bpRaster.getDataBitOffset(), // in bits, NOT bytes! (needs special attention in native |
| // code!) |
| bpRaster.getWidth(), |
| bpRaster.getHeight(), |
| bpRaster.getPixelBitStride(), |
| bpRaster.getScanlineStride() * 8, |
| icm, |
| iType, |
| offsd.fGraphicsStates, |
| offsd.fGraphicsStatesObject, |
| offsd.fImageInfo); |
| |
| //offsd.checkIfLazyPixelConversionDisabled(); |
| offsd.fImageInfoInt.put(kImageStolenIndex, 1); |
| return offsd; |
| } |
| |
| 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); |
| |
| protected native void initCustomRaster(IntBuffer buffer, int width, int height, ByteBuffer graphicsStates, Object graphicsStatesObjects, ByteBuffer imageInfo); |
| |
| public Object getLockObject() { |
| return this.lock; |
| } |
| |
| // Makes the constructor package private instead of public. |
| OSXOffScreenSurfaceData(BufferedImage bufImg, SurfaceType sType) { |
| super(sType, bufImg.getColorModel()); |
| setBounds(0, 0, bufImg.getWidth(), bufImg.getHeight()); |
| |
| this.bim = bufImg; |
| |
| this.fImageInfo = ByteBuffer.allocateDirect(4 * kSizeOfParameters); |
| this.fImageInfo.order(ByteOrder.nativeOrder()); |
| this.fImageInfoInt = this.fImageInfo.asIntBuffer(); |
| |
| this.fImageInfoInt.put(kNeedToSyncFromJavaPixelsIndex, 1); // need to sync from Java the very first time |
| this.fImageInfoInt.put(kNativePixelsChangedIndex, 0); |
| this.fImageInfoInt.put(kImageStolenIndex, 0); |
| |
| this.lock = new Object(); |
| } |
| |
| /** |
| * Performs a copyArea within this surface. |
| */ |
| public boolean copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, int dx, int dy) { |
| // <rdar://problem/4488745> For the Sun2D renderer we should rely on the implementation of the super class. |
| // BufImageSurfaceData.java doesn't have an implementation of copyArea() and relies on the super class. |
| |
| if (sg2d.transformState >= SunGraphics2D.TRANSFORM_TRANSLATESCALE) { |
| return false; |
| } |
| |
| // reset the clip (this is how it works on windows) |
| // we actually can handle a case with any clips but windows ignores the light clip |
| Shape clip = sg2d.getClip(); |
| sg2d.setClip(getBounds()); |
| |
| // clip copyArea |
| Rectangle clippedCopyAreaRect = clipCopyArea(sg2d, x, y, w, h, dx, dy); |
| if (clippedCopyAreaRect == null) { |
| // clipped out |
| return true; |
| } |
| |
| // the rectangle returned from clipCopyArea() is in the coordinate space |
| // of the surface (image) |
| x = clippedCopyAreaRect.x; |
| y = clippedCopyAreaRect.y; |
| w = clippedCopyAreaRect.width; |
| h = clippedCopyAreaRect.height; |
| |
| // copy (dst coordinates are in the coord space of the graphics2d, and |
| // src coordinates are in the coordinate space of the image) |
| // sg2d.drawImage expects the destination rect to be in the coord space |
| // of the graphics2d. <rdar://3746194> (vm) |
| // we need to substract the transX and transY to move it |
| // to the coordinate space of the graphics2d. |
| int dstX = x + dx - sg2d.transX; |
| int dstY = y + dy - sg2d.transY; |
| sg2d.drawImage(this.bim, dstX, dstY, dstX + w, dstY + h, |
| x, y, x + w, y + h, null); |
| |
| // restore the clip |
| sg2d.setClip(clip); |
| |
| return true; |
| } |
| |
| /** |
| * Performs a copyarea from this surface to a buffered image. If null is passed in for the image a new image will be |
| * created. |
| * |
| * Only used by compositor code (private API) |
| */ |
| public BufferedImage copyArea(SunGraphics2D sg2d, int x, int y, int w, int h, BufferedImage dstImage) { |
| // create the destination image if needed |
| if (dstImage == null) { |
| dstImage = getDeviceConfiguration().createCompatibleImage(w, h); |
| } |
| |
| // copy |
| Graphics g = dstImage.createGraphics(); |
| g.drawImage(this.bim, 0, 0, w, h, x, y, x + w, y + h, null); |
| g.dispose(); |
| |
| return dstImage; |
| } |
| |
| public boolean xorSurfacePixels(SunGraphics2D sg2d, BufferedImage srcPixels, int x, int y, int w, int h, int colorXOR) { |
| |
| int type = this.bim.getType(); |
| |
| 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); } |
| |
| return false; |
| } |
| |
| native boolean xorSurfacePixels(SurfaceData src, int colorXOR, int x, int y, int w, int h); |
| |
| public void clearRect(BufferedImage bim, int w, int h) { |
| OSXOffScreenSurfaceData offsd = (OSXOffScreenSurfaceData) (OSXOffScreenSurfaceData.createData(bim)); |
| // offsd.clear(); |
| if (offsd.clearSurfacePixels(w, h) == false) { |
| Graphics2D g = bim.createGraphics(); |
| g.setComposite(AlphaComposite.Clear); |
| g.fillRect(0, 0, w, h); |
| g.dispose(); |
| } |
| } |
| |
| native boolean clearSurfacePixels(int w, int h); |
| |
| // 04/06/04 cmc: radr://3612381 Graphics.drawImage ignores bgcolor parameter. |
| // getCopyWithBgColor returns a new version of an image, drawn with a background |
| // color. Called by blitImage in OSXSurfaceData.java. |
| BufferedImage copyWithBgColor_cache = null; |
| |
| public SurfaceData getCopyWithBgColor(Color bgColor) { |
| int bimW = this.bim.getWidth(); |
| int bimH = this.bim.getHeight(); |
| |
| if ((this.copyWithBgColor_cache == null) |
| || (this.copyWithBgColor_cache.getWidth() < bimW) || (this.copyWithBgColor_cache.getHeight() < bimH)) { |
| GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); |
| this.copyWithBgColor_cache = gc.createCompatibleImage(bimW, bimH); |
| } |
| |
| Graphics g2 = this.copyWithBgColor_cache.createGraphics(); |
| g2.setColor(bgColor); |
| g2.fillRect(0, 0, bimW, bimH); |
| g2.drawImage(this.bim, 0, 0, bimW, bimH, null); |
| g2.dispose(); |
| |
| return getSurfaceData(this.copyWithBgColor_cache); |
| } |
| |
| /** |
| * Invoked before the raster's contents are to be read (via one of the modifier methods in Raster such as |
| * getPixel()) |
| */ |
| public void rasterRead() { |
| if (fImageInfoInt.get(kNativePixelsChangedIndex) == 1) { |
| syncToJavaPixels(); |
| } |
| } |
| |
| /** |
| * Invoked before the raster's contents are to be written to (via one of the modifier methods in Raster such as |
| * setPixel()) |
| */ |
| public void rasterWrite() { |
| if (fImageInfoInt.get(kNativePixelsChangedIndex) == 1) { |
| syncToJavaPixels(); |
| } |
| |
| fImageInfoInt.put(kNeedToSyncFromJavaPixelsIndex, 1); // the pixels will change |
| } |
| |
| private void syncFromCustom() { |
| |
| } |
| |
| private void syncToCustom() { |
| |
| } |
| // /** |
| // * Invoked when the raster's contents will be taken (via the Raster.getDataBuffer() method) |
| // */ |
| // public void rasterStolen() { |
| // fImageInfoInt.put(kImageStolenIndex, 1); // this means we must convert between Java and native pixels every |
| // // single primitive! (very expensive) |
| // if (fImageInfoInt.get(kNativePixelsChangedIndex) == 1) { |
| // syncToJavaPixels(); |
| // } |
| // |
| // // we know the pixels have been stolen, no need to listen for changes any more |
| //// if (this.bufImgSunRaster != null) { |
| //// this.bufImgSunRaster.setRasterListener(null); |
| //// } |
| // } |
| |
| private native void syncToJavaPixels(); |
| |
| // we need to refer to rasters often, so cache them |
| void cacheRasters(BufferedImage bim) { |
| this.bufImgRaster = bim.getRaster(); |
| if (this.bufImgRaster instanceof SunWritableRaster) { |
| this.bufImgSunRaster = (SunWritableRaster) this.bufImgRaster; |
| } |
| } |
| |
| // void setRasterListener() { |
| // if (this.bufImgSunRaster != null) { |
| // this.bufImgSunRaster.setRasterListener(this); |
| // |
| // Raster parentRaster = this.bufImgSunRaster.getParent(); |
| // if (parentRaster != null) { |
| // if (parentRaster instanceof SunWritableRaster) { |
| // // mark subimages stolen to turn off lazy pixel conversion (gznote: can we do better here?) |
| // ((SunWritableRaster) parentRaster).notifyStolen(); |
| // } |
| // rasterStolen(); |
| // } |
| // } else { |
| // // it's a custom image (non-natively supported) and we can not set a raster listener |
| // // so mark the image as stolen - this will turn off LazyPixelConversion optimization (slow, but correct) |
| // rasterStolen(); |
| // } |
| // } |
| } |