J. Duke | 319a3b9 | 2007-12-01 00:00:00 +0000 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright 1999-2007 Sun Microsystems, Inc. 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. Sun designates this |
| 8 | * particular file as subject to the "Classpath" exception as provided |
| 9 | * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
| 22 | * CA 95054 USA or visit www.sun.com if you need additional information or |
| 23 | * have any questions. |
| 24 | */ |
| 25 | |
| 26 | package sun.awt.image; |
| 27 | |
| 28 | import java.awt.Color; |
| 29 | import java.awt.Rectangle; |
| 30 | import java.awt.GraphicsConfiguration; |
| 31 | import java.awt.image.ColorModel; |
| 32 | import java.awt.image.SampleModel; |
| 33 | import java.awt.image.DirectColorModel; |
| 34 | import java.awt.image.IndexColorModel; |
| 35 | import java.awt.image.Raster; |
| 36 | import java.awt.image.BufferedImage; |
| 37 | import java.awt.image.DataBuffer; |
| 38 | |
| 39 | import sun.java2d.SurfaceData; |
| 40 | import sun.java2d.SunGraphics2D; |
| 41 | import sun.java2d.StateTrackable; |
| 42 | import sun.java2d.StateTracker; |
| 43 | import sun.java2d.loops.SurfaceType; |
| 44 | import sun.java2d.loops.CompositeType; |
| 45 | import sun.java2d.loops.RenderLoops; |
| 46 | |
| 47 | public class BufImgSurfaceData extends SurfaceData { |
| 48 | BufferedImage bufImg; |
| 49 | private BufferedImageGraphicsConfig graphicsConfig; |
| 50 | RenderLoops solidloops; |
| 51 | |
| 52 | private static native void initIDs(Class ICM); |
| 53 | |
| 54 | private static final int DCM_RGBX_RED_MASK = 0xff000000; |
| 55 | private static final int DCM_RGBX_GREEN_MASK = 0x00ff0000; |
| 56 | private static final int DCM_RGBX_BLUE_MASK = 0x0000ff00; |
| 57 | private static final int DCM_555X_RED_MASK = 0xF800; |
| 58 | private static final int DCM_555X_GREEN_MASK = 0x07C0; |
| 59 | private static final int DCM_555X_BLUE_MASK = 0x003E; |
| 60 | private static final int DCM_4444_RED_MASK = 0x0f00; |
| 61 | private static final int DCM_4444_GREEN_MASK = 0x00f0; |
| 62 | private static final int DCM_4444_BLUE_MASK = 0x000f; |
| 63 | private static final int DCM_4444_ALPHA_MASK = 0xf000; |
| 64 | private static final int DCM_ARGBBM_ALPHA_MASK = 0x01000000; |
| 65 | private static final int DCM_ARGBBM_RED_MASK = 0x00ff0000; |
| 66 | private static final int DCM_ARGBBM_GREEN_MASK = 0x0000ff00; |
| 67 | private static final int DCM_ARGBBM_BLUE_MASK = 0x000000ff; |
| 68 | |
| 69 | static { |
| 70 | initIDs(IndexColorModel.class); |
| 71 | } |
| 72 | |
| 73 | public static SurfaceData createData(BufferedImage bufImg) { |
| 74 | if (bufImg == null) { |
| 75 | throw new NullPointerException("BufferedImage cannot be null"); |
| 76 | } |
| 77 | SurfaceData sData; |
| 78 | ColorModel cm = bufImg.getColorModel(); |
| 79 | int type = bufImg.getType(); |
| 80 | // REMIND: Check the image type and pick an appropriate subclass |
| 81 | switch (type) { |
| 82 | case BufferedImage.TYPE_INT_BGR: |
| 83 | sData = createDataIC(bufImg, SurfaceType.IntBgr); |
| 84 | break; |
| 85 | case BufferedImage.TYPE_INT_RGB: |
| 86 | sData = createDataIC(bufImg, SurfaceType.IntRgb); |
| 87 | break; |
| 88 | case BufferedImage.TYPE_INT_ARGB: |
| 89 | sData = createDataIC(bufImg, SurfaceType.IntArgb); |
| 90 | break; |
| 91 | case BufferedImage.TYPE_INT_ARGB_PRE: |
| 92 | sData = createDataIC(bufImg, SurfaceType.IntArgbPre); |
| 93 | break; |
| 94 | case BufferedImage.TYPE_3BYTE_BGR: |
| 95 | sData = createDataBC(bufImg, SurfaceType.ThreeByteBgr, 2); |
| 96 | break; |
| 97 | case BufferedImage.TYPE_4BYTE_ABGR: |
| 98 | sData = createDataBC(bufImg, SurfaceType.FourByteAbgr, 3); |
| 99 | break; |
| 100 | case BufferedImage.TYPE_4BYTE_ABGR_PRE: |
| 101 | sData = createDataBC(bufImg, SurfaceType.FourByteAbgrPre, 3); |
| 102 | break; |
| 103 | case BufferedImage.TYPE_USHORT_565_RGB: |
| 104 | sData = createDataSC(bufImg, SurfaceType.Ushort565Rgb, null); |
| 105 | break; |
| 106 | case BufferedImage.TYPE_USHORT_555_RGB: |
| 107 | sData = createDataSC(bufImg, SurfaceType.Ushort555Rgb, null); |
| 108 | break; |
| 109 | case BufferedImage.TYPE_BYTE_INDEXED: |
| 110 | { |
| 111 | SurfaceType sType; |
| 112 | switch (cm.getTransparency()) { |
| 113 | case OPAQUE: |
| 114 | if (isOpaqueGray((IndexColorModel)cm)) { |
| 115 | sType = SurfaceType.Index8Gray; |
| 116 | } else { |
| 117 | sType = SurfaceType.ByteIndexedOpaque; |
| 118 | } |
| 119 | break; |
| 120 | case BITMASK: |
| 121 | sType = SurfaceType.ByteIndexedBm; |
| 122 | break; |
| 123 | case TRANSLUCENT: |
| 124 | sType = SurfaceType.ByteIndexed; |
| 125 | break; |
| 126 | default: |
| 127 | throw new InternalError("Unrecognized transparency"); |
| 128 | } |
| 129 | sData = createDataBC(bufImg, sType, 0); |
| 130 | } |
| 131 | break; |
| 132 | case BufferedImage.TYPE_BYTE_GRAY: |
| 133 | sData = createDataBC(bufImg, SurfaceType.ByteGray, 0); |
| 134 | break; |
| 135 | case BufferedImage.TYPE_USHORT_GRAY: |
| 136 | sData = createDataSC(bufImg, SurfaceType.UshortGray, null); |
| 137 | break; |
| 138 | case BufferedImage.TYPE_BYTE_BINARY: |
| 139 | { |
| 140 | SurfaceType sType; |
| 141 | SampleModel sm = bufImg.getRaster().getSampleModel(); |
| 142 | switch (sm.getSampleSize(0)) { |
| 143 | case 1: |
| 144 | sType = SurfaceType.ByteBinary1Bit; |
| 145 | break; |
| 146 | case 2: |
| 147 | sType = SurfaceType.ByteBinary2Bit; |
| 148 | break; |
| 149 | case 4: |
| 150 | sType = SurfaceType.ByteBinary4Bit; |
| 151 | break; |
| 152 | default: |
| 153 | throw new InternalError("Unrecognized pixel size"); |
| 154 | } |
| 155 | sData = createDataBP(bufImg, sType); |
| 156 | } |
| 157 | break; |
| 158 | case BufferedImage.TYPE_CUSTOM: |
| 159 | default: |
| 160 | { |
| 161 | Raster raster = bufImg.getRaster(); |
| 162 | int numBands = raster.getNumBands(); |
| 163 | if (raster instanceof IntegerComponentRaster && |
| 164 | raster.getNumDataElements() == 1 && |
| 165 | ((IntegerComponentRaster)raster).getPixelStride() == 1) |
| 166 | { |
| 167 | SurfaceType sType = SurfaceType.AnyInt; |
| 168 | if (cm instanceof DirectColorModel) { |
| 169 | DirectColorModel dcm = (DirectColorModel) cm; |
| 170 | int aMask = dcm.getAlphaMask(); |
| 171 | int rMask = dcm.getRedMask(); |
| 172 | int gMask = dcm.getGreenMask(); |
| 173 | int bMask = dcm.getBlueMask(); |
| 174 | if (numBands == 3 && |
| 175 | aMask == 0 && |
| 176 | rMask == DCM_RGBX_RED_MASK && |
| 177 | gMask == DCM_RGBX_GREEN_MASK && |
| 178 | bMask == DCM_RGBX_BLUE_MASK) |
| 179 | { |
| 180 | sType = SurfaceType.IntRgbx; |
| 181 | } else if (numBands == 4 && |
| 182 | aMask == DCM_ARGBBM_ALPHA_MASK && |
| 183 | rMask == DCM_ARGBBM_RED_MASK && |
| 184 | gMask == DCM_ARGBBM_GREEN_MASK && |
| 185 | bMask == DCM_ARGBBM_BLUE_MASK) |
| 186 | { |
| 187 | sType = SurfaceType.IntArgbBm; |
| 188 | } else { |
| 189 | sType = SurfaceType.AnyDcm; |
| 190 | } |
| 191 | } |
| 192 | sData = createDataIC(bufImg, sType); |
| 193 | break; |
| 194 | } else if (raster instanceof ShortComponentRaster && |
| 195 | raster.getNumDataElements() == 1 && |
| 196 | ((ShortComponentRaster)raster).getPixelStride() == 1) |
| 197 | { |
| 198 | SurfaceType sType = SurfaceType.AnyShort; |
| 199 | IndexColorModel icm = null; |
| 200 | if (cm instanceof DirectColorModel) { |
| 201 | DirectColorModel dcm = (DirectColorModel) cm; |
| 202 | int aMask = dcm.getAlphaMask(); |
| 203 | int rMask = dcm.getRedMask(); |
| 204 | int gMask = dcm.getGreenMask(); |
| 205 | int bMask = dcm.getBlueMask(); |
| 206 | if (numBands == 3 && |
| 207 | aMask == 0 && |
| 208 | rMask == DCM_555X_RED_MASK && |
| 209 | gMask == DCM_555X_GREEN_MASK && |
| 210 | bMask == DCM_555X_BLUE_MASK) |
| 211 | { |
| 212 | sType = SurfaceType.Ushort555Rgbx; |
| 213 | } else |
| 214 | if (numBands == 4 && |
| 215 | aMask == DCM_4444_ALPHA_MASK && |
| 216 | rMask == DCM_4444_RED_MASK && |
| 217 | gMask == DCM_4444_GREEN_MASK && |
| 218 | bMask == DCM_4444_BLUE_MASK) |
| 219 | { |
| 220 | sType = SurfaceType.Ushort4444Argb; |
| 221 | } |
| 222 | } else if (cm instanceof IndexColorModel) { |
| 223 | icm = (IndexColorModel)cm; |
| 224 | if (icm.getPixelSize() == 12) { |
| 225 | if (isOpaqueGray(icm)) { |
| 226 | sType = SurfaceType.Index12Gray; |
| 227 | } else { |
| 228 | sType = SurfaceType.UshortIndexed; |
| 229 | } |
| 230 | } else { |
| 231 | icm = null; |
| 232 | } |
| 233 | } |
| 234 | sData = createDataSC(bufImg, sType, icm); |
| 235 | break; |
| 236 | } |
| 237 | sData = new BufImgSurfaceData(raster.getDataBuffer(), |
| 238 | bufImg, SurfaceType.Custom); |
| 239 | } |
| 240 | break; |
| 241 | } |
| 242 | ((BufImgSurfaceData) sData).initSolidLoops(); |
| 243 | return sData; |
| 244 | } |
| 245 | |
| 246 | public static SurfaceData createData(Raster ras, ColorModel cm) { |
| 247 | throw new InternalError("SurfaceData not implemented for Raster/CM"); |
| 248 | } |
| 249 | |
| 250 | public static SurfaceData createDataIC(BufferedImage bImg, |
| 251 | SurfaceType sType) { |
| 252 | IntegerComponentRaster icRaster = |
| 253 | (IntegerComponentRaster)bImg.getRaster(); |
| 254 | BufImgSurfaceData bisd = |
| 255 | new BufImgSurfaceData(icRaster.getDataBuffer(), bImg, sType); |
| 256 | bisd.initRaster(icRaster.getDataStorage(), |
| 257 | icRaster.getDataOffset(0) * 4, 0, |
| 258 | icRaster.getWidth(), |
| 259 | icRaster.getHeight(), |
| 260 | icRaster.getPixelStride() * 4, |
| 261 | icRaster.getScanlineStride() * 4, |
| 262 | null); |
| 263 | return bisd; |
| 264 | } |
| 265 | |
| 266 | public static SurfaceData createDataSC(BufferedImage bImg, |
| 267 | SurfaceType sType, |
| 268 | IndexColorModel icm) { |
| 269 | ShortComponentRaster scRaster = |
| 270 | (ShortComponentRaster)bImg.getRaster(); |
| 271 | BufImgSurfaceData bisd = |
| 272 | new BufImgSurfaceData(scRaster.getDataBuffer(), bImg, sType); |
| 273 | bisd.initRaster(scRaster.getDataStorage(), |
| 274 | scRaster.getDataOffset(0) * 2, 0, |
| 275 | scRaster.getWidth(), |
| 276 | scRaster.getHeight(), |
| 277 | scRaster.getPixelStride() * 2, |
| 278 | scRaster.getScanlineStride() * 2, |
| 279 | icm); |
| 280 | return bisd; |
| 281 | } |
| 282 | |
| 283 | public static SurfaceData createDataBC(BufferedImage bImg, |
| 284 | SurfaceType sType, |
| 285 | int primaryBank) { |
| 286 | ByteComponentRaster bcRaster = |
| 287 | (ByteComponentRaster)bImg.getRaster(); |
| 288 | BufImgSurfaceData bisd = |
| 289 | new BufImgSurfaceData(bcRaster.getDataBuffer(), bImg, sType); |
| 290 | ColorModel cm = bImg.getColorModel(); |
| 291 | IndexColorModel icm = ((cm instanceof IndexColorModel) |
| 292 | ? (IndexColorModel) cm |
| 293 | : null); |
| 294 | bisd.initRaster(bcRaster.getDataStorage(), |
| 295 | bcRaster.getDataOffset(primaryBank), 0, |
| 296 | bcRaster.getWidth(), |
| 297 | bcRaster.getHeight(), |
| 298 | bcRaster.getPixelStride(), |
| 299 | bcRaster.getScanlineStride(), |
| 300 | icm); |
| 301 | return bisd; |
| 302 | } |
| 303 | |
| 304 | public static SurfaceData createDataBP(BufferedImage bImg, |
| 305 | SurfaceType sType) { |
| 306 | BytePackedRaster bpRaster = |
| 307 | (BytePackedRaster)bImg.getRaster(); |
| 308 | BufImgSurfaceData bisd = |
| 309 | new BufImgSurfaceData(bpRaster.getDataBuffer(), bImg, sType); |
| 310 | ColorModel cm = bImg.getColorModel(); |
| 311 | IndexColorModel icm = ((cm instanceof IndexColorModel) |
| 312 | ? (IndexColorModel) cm |
| 313 | : null); |
| 314 | bisd.initRaster(bpRaster.getDataStorage(), |
| 315 | bpRaster.getDataBitOffset() / 8, |
| 316 | bpRaster.getDataBitOffset() & 7, |
| 317 | bpRaster.getWidth(), |
| 318 | bpRaster.getHeight(), |
| 319 | 0, |
| 320 | bpRaster.getScanlineStride(), |
| 321 | icm); |
| 322 | return bisd; |
| 323 | } |
| 324 | |
| 325 | public RenderLoops getRenderLoops(SunGraphics2D sg2d) { |
| 326 | if (sg2d.paintState <= sg2d.PAINT_ALPHACOLOR && |
| 327 | sg2d.compositeState <= sg2d.COMP_ISCOPY) |
| 328 | { |
| 329 | return solidloops; |
| 330 | } |
| 331 | return super.getRenderLoops(sg2d); |
| 332 | } |
| 333 | |
| 334 | public java.awt.image.Raster getRaster(int x, int y, int w, int h) { |
| 335 | return bufImg.getRaster(); |
| 336 | } |
| 337 | |
| 338 | /** |
| 339 | * Initializes the native Ops pointer. |
| 340 | */ |
| 341 | protected native void initRaster(Object theArray, |
| 342 | int offset, |
| 343 | int bitoffset, |
| 344 | int width, |
| 345 | int height, |
| 346 | int pixStr, |
| 347 | int scanStr, |
| 348 | IndexColorModel icm); |
| 349 | |
| 350 | public BufImgSurfaceData(DataBuffer db, |
| 351 | BufferedImage bufImg, SurfaceType sType) |
| 352 | { |
| 353 | super(SunWritableRaster.stealTrackable(db), |
| 354 | sType, bufImg.getColorModel()); |
| 355 | this.bufImg = bufImg; |
| 356 | } |
| 357 | |
| 358 | public void initSolidLoops() { |
| 359 | this.solidloops = getSolidLoops(getSurfaceType()); |
| 360 | } |
| 361 | |
| 362 | private static final int CACHE_SIZE = 5; |
| 363 | private static RenderLoops loopcache[] = new RenderLoops[CACHE_SIZE]; |
| 364 | private static SurfaceType typecache[] = new SurfaceType[CACHE_SIZE]; |
| 365 | public static synchronized RenderLoops getSolidLoops(SurfaceType type) { |
| 366 | for (int i = CACHE_SIZE - 1; i >= 0; i--) { |
| 367 | SurfaceType t = typecache[i]; |
| 368 | if (t == type) { |
| 369 | return loopcache[i]; |
| 370 | } else if (t == null) { |
| 371 | break; |
| 372 | } |
| 373 | } |
| 374 | RenderLoops l = makeRenderLoops(SurfaceType.OpaqueColor, |
| 375 | CompositeType.SrcNoEa, |
| 376 | type); |
| 377 | System.arraycopy(loopcache, 1, loopcache, 0, CACHE_SIZE-1); |
| 378 | System.arraycopy(typecache, 1, typecache, 0, CACHE_SIZE-1); |
| 379 | loopcache[CACHE_SIZE - 1] = l; |
| 380 | typecache[CACHE_SIZE - 1] = type; |
| 381 | return l; |
| 382 | } |
| 383 | |
| 384 | public SurfaceData getReplacement() { |
| 385 | // BufImgSurfaceData objects should never lose their contents, |
| 386 | // so this method should never be called. |
| 387 | return restoreContents(bufImg); |
| 388 | } |
| 389 | |
| 390 | public synchronized GraphicsConfiguration getDeviceConfiguration() { |
| 391 | if (graphicsConfig == null) { |
| 392 | graphicsConfig = BufferedImageGraphicsConfig.getConfig(bufImg); |
| 393 | } |
| 394 | return graphicsConfig; |
| 395 | } |
| 396 | |
| 397 | public java.awt.Rectangle getBounds() { |
| 398 | return new Rectangle(bufImg.getWidth(), bufImg.getHeight()); |
| 399 | } |
| 400 | |
| 401 | protected void checkCustomComposite() { |
| 402 | // BufferedImages always allow Custom Composite objects since |
| 403 | // their pixels are immediately retrievable anyway. |
| 404 | } |
| 405 | |
| 406 | public static native void freeNativeICMData(IndexColorModel icm); |
| 407 | |
| 408 | /** |
| 409 | * Returns destination Image associated with this SurfaceData. |
| 410 | */ |
| 411 | public Object getDestination() { |
| 412 | return bufImg; |
| 413 | } |
| 414 | } |