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 #import "ImageSurfaceData.h"
  27 
  28 #import "java_awt_Transparency.h"
  29 #import "java_awt_image_BufferedImage.h"
  30 #import "sun_awt_image_BufImgSurfaceData.h"
  31 #import "sun_java2d_OSXOffScreenSurfaceData.h"
  32 
  33 #import "ThreadUtilities.h"
  34 #import "JNIUtilities.h"
  35 
  36 #import "BufImgSurfaceData.h"
  37 
  38 //#define DEBUG 1
  39 #if defined DEBUG
  40     #define IMAGE_SURFACE_INLINE
  41     #define PRINT(msg) {fprintf(stderr, "%s\n", msg);fflush(stderr);}
  42 #else
  43     #define IMAGE_SURFACE_INLINE static inline
  44     #define PRINT(msg) {}
  45 #endif
  46 
  47 // same value as defined in Sun's own code
  48 #define XOR_ALPHA_CUTOFF 128
  49 
  50 // for vImage framework headers
  51 #include <Accelerate/Accelerate.h>
  52 
  53 static ContextInfo sDefaultContextInfo[sun_java2d_OSXOffScreenSurfaceData_TYPE_3BYTE_RGB+1] =
  54 {
  55     {YES,    YES,    8,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_CUSTOM            // special case
  56     {YES,    YES,    8,        4,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,        NULL},    // TYPE_INT_RGB
  57     {YES,    YES,    8,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_INT_ARGB
  58     {YES,    YES,    8,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_INT_ARGB_PRE
  59     {YES,    YES,    8,        4,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,        NULL},    // TYPE_INT_BGR
  60     {YES,    NO,        8,        4,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,        NULL},    // TYPE_3BYTE_BGR        // use the default ARGB_PRE context synce we have to sync by hand anyway
  61     {YES,    YES,    8,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_4BYTE_ABGR
  62     {YES,    YES,    8,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_4BYTE_ABGR_PRE
  63 #ifdef __LITTLE_ENDIAN__
  64     {YES,    YES,    5,        2,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder16Host,        NULL},    // TYPE_USHORT_565_RGB
  65     {YES,    YES,    5,        2,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder16Host,        NULL},    // TYPE_USHORT_555_RGB
  66 #else
  67     {YES,    YES,    5,        2,        0,        kCGImageAlphaNoneSkipFirst,                                    NULL},    // TYPE_USHORT_565_RGB
  68     {YES,    YES,    5,        2,        0,        kCGImageAlphaNoneSkipFirst,                                    NULL},    // TYPE_USHORT_555_RGB
  69 #endif
  70     {YES,    YES,    8,        1,        0,        kCGImageAlphaNone,                                            NULL},    // TYPE_BYTE_GRAY
  71     {YES,    NO,        8,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_USHORT_GRAY        // use the default ARGB_PRE context synce we have to sync by hand anyway
  72     {NO,    NO,        8,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_BYTE_BINARY        mapped to TYPE_CUSTOM
  73     {YES,    NO,        8,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_BYTE_INDEXED    // use the default ARGB_PRE context synce we have to sync by hand anyway
  74     {YES,    NO,        8,        4,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,        NULL},    // TYPE_3BYTE_RGB
  75 };
  76 
  77 static ImageInfo sDefaultImageInfo[sun_java2d_OSXOffScreenSurfaceData_TYPE_3BYTE_RGB+1] =
  78 {
  79     {8,        32,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_CUSTOM
  80     {8,        32,        4,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,        NULL},    // TYPE_INT_RGB
  81     {8,        32,        4,        0,        kCGImageAlphaFirst | kCGBitmapByteOrder32Host,                NULL},    // TYPE_INT_ARGB
  82     {8,        32,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_INT_ARGB_PRE
  83     {8,        32,        4,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,        NULL},    // TYPE_INT_BGR
  84     {8,        32,        4,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,        NULL},    // TYPE_3BYTE_BGR
  85     {8,        32,        4,        0,        kCGImageAlphaFirst | kCGBitmapByteOrder32Host,                NULL},    // TYPE_4BYTE_ABGR
  86     {8,        32,        4,        0,        kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host,    NULL},    // TYPE_4BYTE_ABGR_PRE
  87 #ifdef __LITTLE_ENDIAN__
  88     {5,        16,        2,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder16Host,        NULL},    // TYPE_USHORT_565_RGB
  89     {5,        16,        2,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder16Host,        NULL},    // TYPE_USHORT_555_RGB
  90 #else
  91     {5,        16,        2,        0,        kCGImageAlphaNoneSkipFirst,                                    NULL},    // TYPE_USHORT_565_RGB
  92     {5,        16,        2,        0,        kCGImageAlphaNoneSkipFirst,                                    NULL},    // TYPE_USHORT_555_RGB
  93 #endif
  94     {8,        8,        1,        0,        kCGImageAlphaNone,                                            NULL},    // TYPE_BYTE_GRAY
  95     {16,    16,        2,        0,        kCGImageAlphaNone | kCGBitmapByteOrder16Host,                NULL},    // TYPE_USHORT_GRAY
  96     {0,        0,        0,        0,        -1,                                                            NULL},    // TYPE_BYTE_BINARY        mapped to TYPE_CUSTOM
  97     {8,        32,        4,        0,        kCGImageAlphaFirst | kCGBitmapByteOrder32Host,                NULL},    // TYPE_BYTE_INDEXED  // Fully OPAQUE INDEXED images will use kCGImageAlphaNoneSkipFirst for performance reasosn. see <rdar://4224874>
  98     {8,        32,        4,        0,        kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host,        NULL},    // TYPE_3BYTE_RGB
  99 };
 100 
 101 static jfieldID        rgbID;
 102 static jfieldID        mapSizeID;
 103 static jfieldID        CMpDataID;
 104 static jfieldID        allGrayID;
 105 
 106 static jclass jc_OSXOffScreenSurfaceData = NULL;
 107 #define GET_OSXOSD_CLASS() \
 108     GET_CLASS(jc_OSXOffScreenSurfaceData, "sun/java2d/OSXOffScreenSurfaceData");
 109 
 110 CGColorSpaceRef gColorspaceRGB = NULL;
 111 CGColorSpaceRef gColorspaceGray = NULL;
 112 
 113 IMAGE_SURFACE_INLINE void PrintImageInfo(ImageSDOps* isdo)
 114 {
 115     fprintf(stderr, "\n");
 116     fprintf(stderr, "PrintImageInfo:\n");
 117     fprintf(stderr, "\t \n");
 118     //fprintf(stderr, "\t magicID=%d\n", (jint)isdo->magicID);
 119     //fprintf(stderr, "\n");
 120     fprintf(stderr, "\t isdo=%p\n", isdo);
 121     fprintf(stderr, "\t \n");
 122     fprintf(stderr, "\t contextInfo:\n");
 123     fprintf(stderr, "\t        useWindowContextReference=%d\n", isdo->contextInfo.useWindowContextReference);
 124     fprintf(stderr, "\t        canUseJavaPixelsAsContext=%d\n", isdo->contextInfo.canUseJavaPixelsAsContext);
 125     fprintf(stderr, "\t        bitsPerComponent=%ld\n", (long)isdo->contextInfo.bitsPerComponent);
 126     fprintf(stderr, "\t        bytesPerPixel=%ld\n", (long)isdo->contextInfo.bytesPerPixel);
 127     fprintf(stderr, "\t        bytesPerRow=%ld\n", (long)isdo->contextInfo.bytesPerRow);
 128     fprintf(stderr, "\t        alphaInfo=%ld\n", (long)isdo->contextInfo.alphaInfo);
 129     fprintf(stderr, "\t \n");
 130     fprintf(stderr, "\t imageInfo:\n");
 131     fprintf(stderr, "\t        bitsPerComponent=%ld\n", (long)isdo->imageInfo.bitsPerComponent);
 132     fprintf(stderr, "\t        bitsPerPixel=%ld\n", (long)isdo->imageInfo.bitsPerPixel);
 133     fprintf(stderr, "\t        bytesPerPixel=%ld\n", (long)isdo->imageInfo.bytesPerPixel);
 134     fprintf(stderr, "\t        bytesPerRow=%ld\n", (long)isdo->imageInfo.bytesPerRow);
 135     fprintf(stderr, "\t        alphaInfo=%ld\n", (long)isdo->imageInfo.alphaInfo);
 136     fprintf(stderr, "\t \n");
 137     fprintf(stderr, "\t isSubImage=%d\n", isdo->isSubImage);
 138     fprintf(stderr, "\t \n");
 139     fprintf(stderr, "\t java info:\n");
 140     fprintf(stderr, "\t        array=%p\n", isdo->array);
 141     fprintf(stderr, "\t        offset=%d\n", (int)isdo->offset);
 142     fprintf(stderr, "\t        width=%d\n", (int)isdo->width);
 143     fprintf(stderr, "\t        height=%d\n", (int)isdo->height);
 144     fprintf(stderr, "\t        javaPixelBytes=%d\n", (int)isdo->javaPixelBytes);
 145     fprintf(stderr, "\t        javaPixelsBytesPerRow=%d\n", (int)isdo->javaPixelsBytesPerRow);
 146     fprintf(stderr, "\t        icm=%p\n", isdo->icm);
 147     fprintf(stderr, "\t        type=%d\n", (int)isdo->type);
 148     fprintf(stderr, "\n");
 149     fprintf(stderr, "\t cgRef=%p\n", isdo->qsdo.cgRef);
 150     fprintf(stderr, "\t nsRef=%p\n", isdo->nsRef);
 151     fprintf(stderr, "\n");
 152     fprintf(stderr, "\t pixelsLocked=%p\n", isdo->pixelsLocked);
 153     fprintf(stderr, "\t pixels=%p\n", isdo->pixels);
 154     fprintf(stderr, "\n");
 155     fprintf(stderr, "\t indexedColorTable=%p\n", isdo->indexedColorTable);
 156     fprintf(stderr, "\t lutData=%p\n", isdo->lutData);
 157     fprintf(stderr, "\t lutDataSize=%u\n", (unsigned)isdo->lutDataSize);
 158     fprintf(stderr, "\n");
 159     fprintf(stderr, "\t nrOfPixelsOwners=%u\n", (unsigned)isdo->nrOfPixelsOwners);
 160     fprintf(stderr, "\n");
 161 }
 162 
 163 // if there is no image created for isdo.imgRef, it creates and image using the isdo.dataProvider
 164 // If there is an image present, this is a no-op
 165 void makeSureImageIsCreated(ImageSDOps* isdo)
 166 {
 167     if (isdo->imgRef == NULL)  // create the image
 168     {
 169         isdo->imgRef = CGImageCreate(isdo->width,
 170                                       isdo->height,
 171                                       isdo->contextInfo.bitsPerComponent,
 172                                       isdo->contextInfo.bytesPerPixel * 8,
 173                                       isdo->contextInfo.bytesPerRow,
 174                                       isdo->contextInfo.colorSpace,
 175                                       isdo->contextInfo.alphaInfo,
 176                                       isdo->dataProvider,
 177                                       NULL,
 178                                       NO,
 179                                       kCGRenderingIntentDefault);
 180     }
 181 }
 182 
 183 IMAGE_SURFACE_INLINE void customPixelsFromJava(JNIEnv *env, ImageSDOps *isdo)
 184 {
 185 PRINT("    customPixelsFromJava")
 186 
 187     SurfaceDataOps *sdo = (SurfaceDataOps*)isdo;
 188     GET_OSXOSD_CLASS();
 189     DECLARE_METHOD(jm_syncFromCustom, jc_OSXOffScreenSurfaceData, "syncFromCustom", "()V");
 190 
 191     (*env)->CallVoidMethod(env, sdo->sdObject, jm_syncFromCustom); // AWT_THREADING Safe (known object)
 192     CHECK_EXCEPTION();
 193 }
 194 
 195 IMAGE_SURFACE_INLINE void copyBits(jint w, jint h, jint javaPixelsBytesPerRow, Pixel8bit *pixelsSrc, jint dstPixelsBytesPerRow, Pixel8bit *pixelsDst)
 196 {
 197 PRINT("    copyBits")
 198 
 199     if (javaPixelsBytesPerRow == dstPixelsBytesPerRow)
 200     {
 201         memcpy(pixelsDst, pixelsSrc, h*javaPixelsBytesPerRow);
 202     }
 203     else
 204     {
 205         register jint y;
 206         for (y=0; y<h; y++)
 207         {
 208             memcpy(pixelsDst, pixelsSrc, dstPixelsBytesPerRow);
 209 
 210             pixelsSrc += javaPixelsBytesPerRow;
 211             pixelsDst += dstPixelsBytesPerRow;
 212         }
 213     }
 214 }
 215 
 216 IMAGE_SURFACE_INLINE void copySwapRandB_32bit_TYPE_4BYTE(jint w, jint h, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel32bit *pixelsSrc, Pixel32bit *pixelsDst, size_t extraBytesPerRow)
 217 {
 218 PRINT("    copySwapRandB_32bit_TYPE_4BYTE")
 219 
 220     register Pixel8bit *p8Bit = NULL;
 221     register jint skip = (javaPixelsBytesPerRow/javaPixelBytes)-w; // in pixelsSrc units
 222     register Pixel32bit pixel, red, blue;
 223     register jint x, y;
 224 
 225     for (y=0; y<h; y++)
 226     {
 227         for (x=0; x<w; x++)
 228         {
 229             pixel = *pixelsSrc++;
 230 
 231 #ifdef __LITTLE_ENDIAN__
 232             pixel = CFSwapInt32BigToHost(pixel);   // the jint is in big endian format, we need to swap the bits
 233 #endif
 234 
 235             red        = (pixel & 0x00ff0000) >> 16; // get original red and shift to new position
 236             blue    = (pixel & 0x000000ff) << 16; // get original blue and shift to new position
 237 
 238             pixel    = (pixel & 0xff00ff00); // erase original red&blue
 239 
 240             pixel    = pixel | red | blue; // construct new pixel
 241 
 242             *pixelsDst++ = pixel;
 243         }
 244         pixelsSrc += skip;
 245 
 246         p8Bit = (Pixel8bit *) pixelsDst;
 247         p8Bit += extraBytesPerRow;
 248         pixelsDst = (Pixel32bit *) p8Bit;
 249     }
 250 }
 251 
 252 
 253 IMAGE_SURFACE_INLINE void copySwapRandB_32bit_TYPE_INT(jint w, jint h, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel32bit *pixelsSrc, Pixel32bit *pixelsDst, size_t extraBytesPerRow)
 254 {
 255 PRINT("    copySwapRandB_32bit_TYPE_INT")
 256 
 257     register Pixel8bit *p8Bit = NULL;
 258     register jint skip = (javaPixelsBytesPerRow/javaPixelBytes)-w; // in pixelsSrc units
 259     register Pixel32bit pixel, red, blue;
 260     register jint x, y;
 261 
 262     for (y=0; y<h; y++)
 263     {
 264         for (x=0; x<w; x++)
 265         {
 266             pixel = *pixelsSrc++;
 267 
 268             red        = (pixel & 0x00ff0000) >> 16; // get original red and shift to new position
 269             blue    = (pixel & 0x000000ff) << 16; // get original blue and shift to new position
 270 
 271             pixel    = (pixel & 0xff00ff00); // erase original red&blue
 272 
 273             pixel    = pixel | red | blue; // construct new pixel
 274 
 275             *pixelsDst++ = pixel;
 276         }
 277         pixelsSrc += skip;
 278 
 279         p8Bit = (Pixel8bit *) pixelsDst;
 280         p8Bit += extraBytesPerRow;
 281         pixelsDst = (Pixel32bit *) p8Bit;
 282     }
 283 }
 284 
 285 
 286 IMAGE_SURFACE_INLINE void copyBGR_24bitToXRGB_32bit(jint w, jint h, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel8bit *pixelsSrc, Pixel32bit *pixelsDst, size_t extraBytesPerRow)
 287 {
 288 PRINT("    copyBGR_24bitToXRGB_32bit")
 289 
 290     register Pixel8bit *p8Bit = NULL;
 291     register jint skip = ((javaPixelsBytesPerRow/javaPixelBytes)-w)*javaPixelBytes; // in pixelsSrc units
 292     register Pixel32bit red, green, blue, pixel;
 293     register jint x, y;
 294 
 295     for (y=0; y<h; y++)
 296     {
 297         for (x=0; x<w; x++)
 298         {
 299             pixel        = *pixelsSrc++;
 300             blue        = pixel << 0;
 301 
 302             pixel        = *pixelsSrc++;
 303             green        = pixel << 8;
 304 
 305             pixel        = *pixelsSrc++;
 306             red            = pixel << 16;
 307 
 308             *pixelsDst    = red | green | blue;
 309 
 310             *pixelsDst = 0xff000000 | *pixelsDst;
 311 
 312             pixelsDst++;
 313         }
 314         pixelsSrc += skip;
 315 
 316         p8Bit = (Pixel8bit *) pixelsDst;
 317         p8Bit += extraBytesPerRow;
 318         pixelsDst = (Pixel32bit *) p8Bit;
 319     }
 320 }
 321 
 322 IMAGE_SURFACE_INLINE void copyRGB_24bitToXRGB_32bit(jint w, jint h, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel8bit *pixelsSrc, Pixel32bit *pixelsDst, size_t extraBytesPerRow)
 323 {
 324 PRINT("    copyRGB_24bitToXRGB_32bit")
 325 
 326     register Pixel8bit *p8Bit = NULL;
 327     register jint skip = ((javaPixelsBytesPerRow/javaPixelBytes)-w)*javaPixelBytes; // in pixelsSrc units
 328     register Pixel32bit red, green, blue, pixel;
 329     register jint x, y;
 330 
 331     for (y=0; y<h; y++)
 332     {
 333         for (x=0; x<w; x++)
 334         {
 335             pixel        = *pixelsSrc++;
 336             red            = pixel << 16;
 337 
 338             pixel        = *pixelsSrc++;
 339             green        = pixel << 8;
 340 
 341             pixel        = *pixelsSrc++;
 342             blue        = pixel << 0;
 343 
 344             *pixelsDst    = red | green | blue;
 345 
 346             *pixelsDst = 0xff000000 | *pixelsDst;
 347 
 348             pixelsDst++;
 349         }
 350         pixelsSrc += skip;
 351 
 352         p8Bit = (Pixel8bit *) pixelsDst;
 353         p8Bit += extraBytesPerRow;
 354         pixelsDst = (Pixel32bit *) p8Bit;
 355     }
 356 }
 357 
 358 IMAGE_SURFACE_INLINE void copyIndexed_8bitToARGB_32bit(jint w, jint h, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel8bit *pixelsSrc,
 359                                                         Pixel32bit* lutdata, Pixel32bit *pixelsDst, size_t extraBytesPerRow)
 360 {
 361 PRINT("    copyIndexed_8bitToARGB_32bit")
 362 
 363     //gznote: how is the performance if the extraBytesPerRow != 0 ?
 364     const vImage_Buffer src = {pixelsSrc, h, w, javaPixelsBytesPerRow};
 365     const vImage_Buffer dest = {pixelsDst, h, w, w*sizeof(Pixel32bit)+extraBytesPerRow};
 366     vImage_Error err = vImageLookupTable_Planar8toPlanarF(&src, &dest, (Pixel_F*)lutdata, kvImageDoNotTile);
 367     if (err != kvImageNoError)
 368     {
 369         fprintf(stderr, "Error in copyIndexed_8bitToARGB_32bit: vImageLookupTable_Planar8toPlanarF returns %ld\n", (long)err);
 370         register Pixel8bit *p8Bit = NULL;
 371         register jint skip = (javaPixelsBytesPerRow/javaPixelBytes)-w; // in pixelsSrc units
 372         register jint x, y;
 373         for (y=0; y<h; y++)
 374         {
 375             for (x=0; x<w; x++)
 376             {
 377                 *pixelsDst++ = lutdata[*pixelsSrc++];        // case 1
 378                 //*pixelsDst++ = *(lutdata + *pixelsSrc++);    // case 2: at best ~1% better than case 1
 379             }
 380             pixelsSrc += skip;
 381 
 382             p8Bit = (Pixel8bit *) pixelsDst;
 383             p8Bit += extraBytesPerRow;
 384             pixelsDst = (Pixel32bit *) p8Bit;
 385         }
 386     }
 387 }
 388 
 389 IMAGE_SURFACE_INLINE void copy565_16bitTo555_16bit(jint w, jint h, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel16bit *pixelsSrc, Pixel16bit *pixelsDst, size_t extraBytesPerRow)
 390 {
 391 PRINT("    copy565_16bitTo555_16bit")
 392 
 393     register Pixel8bit *p8Bit = NULL;
 394     register jint skip = (javaPixelsBytesPerRow/javaPixelBytes)-w; // in pixelsSrc units
 395     register jint green;
 396     register Pixel16bit pixel;
 397     register jint x, y;
 398     for (y=0; y<h; y++)
 399     {
 400         for (x=0; x<w; x++)
 401         {
 402             pixel = *pixelsSrc++;
 403 
 404             green = ((pixel >> 5) & 63);  // rrrrrggggggbbbbb => shift 5 right = 00000rrrrrgggggg => and 63 = 0000000000gggggg
 405             green = ((jint) (((CGFloat) green / 63.0f) * 31.0f)) & 31; // first normalize to value between 0 and 1 and then un-normalize to 5 bit (31 = 0000000000011111)
 406 
 407             *pixelsDst++ = ((pixel&0xf800)>>1) | (green << 5) | (pixel&0x01f);
 408         }
 409         pixelsSrc += skip;
 410 
 411         p8Bit = (Pixel8bit *) pixelsDst;
 412         p8Bit += extraBytesPerRow;
 413         pixelsDst = (Pixel16bit *) p8Bit;
 414     }
 415 }
 416 
 417 
 418 IMAGE_SURFACE_INLINE void customPixelsToJava(JNIEnv *env, ImageSDOps *isdo)
 419 {
 420 PRINT("    customPixelsToJava")
 421 
 422     SurfaceDataOps *sdo = (SurfaceDataOps*)isdo;
 423     GET_OSXOSD_CLASS();
 424     DECLARE_METHOD(jm_syncToCustom, jc_OSXOffScreenSurfaceData, "syncToCustom", "()V");
 425     (*env)->CallVoidMethod(env, sdo->sdObject, jm_syncToCustom); // AWT_THREADING Safe (known object)
 426     CHECK_EXCEPTION();
 427 }
 428 
 429 IMAGE_SURFACE_INLINE void removeAlphaPre_32bit(jint w, jint h, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel32bit *pixelsSrc)
 430 {
 431 PRINT("    removeAlphaPre_32bit")
 432 
 433     register jint skip = (javaPixelsBytesPerRow/javaPixelBytes)-w; // in pixelsSrc units
 434     register Pixel32bit pixel, alpha, red, green, blue;
 435     register jint x, y;
 436 
 437     for (y=0; y<h; y++)
 438     {
 439         for (x=0; x<w; x++)
 440         {
 441             pixel = *pixelsSrc;
 442 
 443             alpha        = (pixel >> 24) & 0xff;
 444 
 445             if (alpha != 0)
 446             {
 447                 // get color components
 448                 red            = (pixel >> 16) & 0xff;
 449                 green        = (pixel >> 8) & 0xff;
 450                 blue        = (pixel >> 0) & 0xff;
 451 
 452                 // remove alpha pre
 453                 red            = ((red * 0xff) + 0x7f) / alpha;
 454                 green        = ((green * 0xff) + 0x7f) / alpha;
 455                 blue        = ((blue * 0xff) + 0x7f) / alpha;
 456 
 457                 // clamp
 458                 red            = (red <= 0xff) ? red : 0xff;
 459                 green        = (green <= 0xff) ? green : 0xff;
 460                 blue        = (blue <= 0xff) ? blue : 0xff;
 461 
 462                 *pixelsSrc++ = (alpha<<24) | (red<<16) | (green<<8) | blue; // construct new pixel
 463             }
 464             else
 465             {
 466                 *pixelsSrc++ = 0;
 467             }
 468         }
 469 
 470         pixelsSrc += skip;
 471     }
 472 }
 473 
 474 IMAGE_SURFACE_INLINE void swapRandBAndRemoveAlphaPre_32bit(jint w, jint h, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel32bit *pixelsSrc)
 475 {
 476 PRINT("    swapRandBAndRemoveAlphaPre_32bit")
 477 
 478     register jint skip = (javaPixelsBytesPerRow/javaPixelBytes)-w; // in pixelsSrc units
 479     register Pixel32bit pixel, alpha, red, green, blue;
 480     register jint x, y;
 481 
 482     for (y=0; y<h; y++)
 483     {
 484         for (x=0; x<w; x++)
 485         {
 486             pixel = *pixelsSrc;
 487 
 488             alpha        = (pixel & 0xff000000) >> 24;
 489 
 490             if (alpha != 0)
 491             {
 492                 // get color components
 493                 red            = (pixel & 0x00ff0000) >> 16;
 494                 green        = (pixel & 0x0000ff00) >> 8;
 495                 blue        = (pixel & 0x000000ff) >> 0;
 496 
 497                 // remove alpha pre
 498                 red            = ((red * 0xff) + 0x7f) / alpha;
 499                 green        = ((green * 0xff) + 0x7f) / alpha;
 500                 blue        = ((blue * 0xff) + 0x7f) / alpha;
 501 
 502                 // clamp
 503                 red            = (red <= 0xff) ? red : 0xff;
 504                 green        = (green <= 0xff) ? green : 0xff;
 505                 blue        = (blue <= 0xff) ? blue : 0xff;
 506 
 507                 pixel = (alpha<<24) | (blue<<16) | (green<<8) | red; // construct new pixel
 508 
 509 #ifdef __LITTLE_ENDIAN__
 510                 pixel = CFSwapInt32HostToBig(pixel);  // the jint is little endian, we need to swap the bits before we send it back to Java
 511 #endif
 512 
 513                 *pixelsSrc++ = pixel;
 514             }
 515             else
 516             {
 517                 *pixelsSrc++ = 0;
 518             }
 519         }
 520 
 521         pixelsSrc += skip;
 522     }
 523 }
 524 
 525 IMAGE_SURFACE_INLINE void swapRandB_32bit_TYPE_INT(jint w, jint h, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel32bit *pixelsSrc)
 526 {
 527 PRINT("    swapRandB_32bit_TYPE_INT")
 528 
 529     register jint skip = (javaPixelsBytesPerRow/javaPixelBytes)-w; // in pixelsSrc units
 530     register Pixel32bit pixel, red, blue;
 531     register jint x, y;
 532 
 533     for (y=0; y<h; y++)
 534     {
 535         for (x=0; x<w; x++)
 536         {
 537             pixel = *pixelsSrc;
 538 
 539             red        = (pixel & 0x00ff0000) >> 16; // get original red and shift to new position
 540             blue    = (pixel & 0x000000ff) << 16; // get original blue and shift to new position
 541 
 542             pixel    = (pixel & 0xff00ff00); // erase original red&blue
 543 
 544             pixel    = pixel | red | blue; // construct new pixel
 545 
 546             *pixelsSrc++ = pixel;
 547         }
 548 
 549         pixelsSrc += skip;
 550     }
 551 }
 552 
 553 IMAGE_SURFACE_INLINE void swapRandB_32bit_TYPE_4BYTE(jint w, jint h, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel32bit *pixelsSrc)
 554 {
 555 PRINT("    swapRandB_32bit_TYPE_4BYTE")
 556 
 557     register jint skip = (javaPixelsBytesPerRow/javaPixelBytes)-w; // in pixelsSrc units
 558     register Pixel32bit pixel, red, blue;
 559     register jint x, y;
 560 
 561     for (y=0; y<h; y++)
 562     {
 563         for (x=0; x<w; x++)
 564         {
 565             pixel = *pixelsSrc;
 566 
 567             red        = (pixel & 0x00ff0000) >> 16; // get original red and shift to new position
 568             blue    = (pixel & 0x000000ff) << 16; // get original blue and shift to new position
 569 
 570             pixel    = (pixel & 0xff00ff00); // erase original red&blue
 571 
 572             pixel    = pixel | red | blue; // construct new pixel
 573 
 574 #ifdef __LITTLE_ENDIAN__
 575             pixel = CFSwapInt32HostToBig(pixel); // the jint is little endian, we need to swap the bits before we send it back to Java
 576 #endif
 577 
 578             *pixelsSrc++ = pixel;
 579         }
 580 
 581         pixelsSrc += skip;
 582     }
 583 }
 584 
 585 IMAGE_SURFACE_INLINE void map555_16bitTo565_16bit(jint w, jint h, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel16bit *pixelsSrc)
 586 {
 587 PRINT("    map555_16bitTo565_16bit")
 588     register jint skip = (javaPixelsBytesPerRow/javaPixelBytes)-w; // in pixelsSrc units
 589     register jint green;
 590     register Pixel16bit pixel;
 591     register jint x, y;
 592     for (y=0; y<h; y++)
 593     {
 594         for (x=0; x<w; x++)
 595         {
 596             pixel = *pixelsSrc;
 597 
 598             green = ((pixel >> 5)  & 31);   // rrrrrgggggbbbbb => shift 5 right = 000000rrrrrggggg => and 31 = 00000000000ggggg
 599             green = ((jint) (((CGFloat) green / 31.0f) * 63.0f)) & 63; // first normalize between 0 and 1 and then un-normalize to 6 bit (63 = 0000000000111111)
 600 
 601             *pixelsSrc++ = ((pixel&0x7c00)<<1) | (green << 5) | (pixel&0x01f);
 602         }
 603 
 604         pixelsSrc += skip;
 605     }
 606 }
 607 
 608 IMAGE_SURFACE_INLINE void copyARGB_PRE_32bitToBGR_24bit(jint w, jint h, jint nativePixelsBytesPerRow, Pixel32bit *pixelsSrc, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel8bit *pixelsDst)
 609 {
 610 PRINT("    copyARGB_PRE_32bitToBGR_24bit")
 611 
 612     static const jint mask = 0x000000ff;
 613     register jint skipSrc = (nativePixelsBytesPerRow/sizeof(Pixel32bit))-w; // in pixelsSrc units
 614     register jint skipDst = ((javaPixelsBytesPerRow/javaPixelBytes)-w)*javaPixelBytes; // in pixelsDst units
 615     register Pixel32bit pixel, alpha, red, green, blue;
 616     register jint x, y;
 617 
 618     for (y=0; y<h; y++)
 619     {
 620         for (x=0; x<w; x++)
 621         {
 622             pixel = *pixelsSrc;
 623 
 624             alpha        = (pixel >> 24) & mask;
 625 
 626             if (alpha != 0)
 627             {
 628                 // extract color components
 629                 red            = (pixel >> 16) & mask;
 630                 green        = (pixel >> 8) & mask;
 631                 blue        = (pixel >> 0) & mask;
 632 
 633                 // remove alpha pre
 634                 red            = ((red * 0xff) + 0x7f) / alpha;
 635                 green        = ((green * 0xff) + 0x7f) / alpha;
 636                 blue        = ((blue * 0xff) + 0x7f) / alpha;
 637 
 638                 // clamp
 639                 *pixelsDst++ = (blue <= 0xff) ? blue : 0xff;
 640                 *pixelsDst++ = (green <= 0xff) ? green : 0xff;
 641                 *pixelsDst++ = (red <= 0xff) ? red : 0xff;
 642             }
 643             else
 644             {
 645                 *pixelsDst++ = 0; // blue
 646                 *pixelsDst++ = 0; // green
 647                 *pixelsDst++ = 0; // red
 648             }
 649 
 650             pixelsSrc++;
 651         }
 652 
 653         pixelsSrc += skipSrc;
 654         pixelsDst += skipDst;
 655     }
 656 }
 657 
 658 
 659 IMAGE_SURFACE_INLINE void copyARGB_PRE_32bitToRGB_24bit(jint w, jint h, jint nativePixelsBytesPerRow, Pixel32bit *pixelsSrc, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel8bit *pixelsDst)
 660 {
 661     PRINT("    copyARGB_PRE_32bitToRGB_24bit")
 662 
 663     static const jint mask = 0x000000ff;
 664     register jint skipSrc = (nativePixelsBytesPerRow/sizeof(Pixel32bit))-w; // in pixelsSrc units
 665     register jint skipDst = ((javaPixelsBytesPerRow/javaPixelBytes)-w)*javaPixelBytes; // in pixelsDst units
 666     register Pixel32bit pixel, alpha, red, green, blue;
 667     register jint x, y;
 668 
 669     for (y=0; y<h; y++)
 670     {
 671         for (x=0; x<w; x++)
 672         {
 673             pixel = *pixelsSrc;
 674 
 675             alpha        = (pixel >> 24) & mask;
 676 
 677             if (alpha != 0)
 678             {
 679                 // extract color components
 680                 red            = (pixel >> 16) & mask;
 681                 green        = (pixel >> 8) & mask;
 682                 blue        = (pixel >> 0) & mask;
 683 
 684                 // remove alpha pre
 685                 red            = ((red * 0xff) + 0x7f) / alpha;
 686                 green        = ((green * 0xff) + 0x7f) / alpha;
 687                 blue        = ((blue * 0xff) + 0x7f) / alpha;
 688 
 689                 // clamp
 690                 *pixelsDst++ = (red <= 0xff) ? red : 0xff;
 691                 *pixelsDst++ = (green <= 0xff) ? green : 0xff;
 692                 *pixelsDst++ = (blue <= 0xff) ? blue : 0xff;
 693             }
 694             else
 695             {
 696                 *pixelsDst++ = 0; // blue
 697                 *pixelsDst++ = 0; // green
 698                 *pixelsDst++ = 0; // red
 699             }
 700 
 701             pixelsSrc++;
 702         }
 703 
 704         pixelsSrc += skipSrc;
 705         pixelsDst += skipDst;
 706     }
 707 }
 708 
 709 
 710 // gray = 0.3red + 0.59green + 0.11blue - NTSC standard (according to Luke Wallis)
 711 IMAGE_SURFACE_INLINE void copyARGB_PRE_32bitToGray_16bit(jint w, jint h, jint nativePixelsBytesPerRow, Pixel32bit *pixelsSrc, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel16bit *pixelsDst)
 712 {
 713 PRINT("    copyARGB_PRE_32bitToGray_16bit")
 714 
 715     static const jint mask = 0x000000ff;
 716     register jint skipSrc = (nativePixelsBytesPerRow/sizeof(Pixel32bit))-w; // in pixelsSrc units
 717     register jint skipDst = (javaPixelsBytesPerRow/javaPixelBytes)-w; // in pixelsDst units
 718     register Pixel32bit alpha;
 719     register Pixel32bit pixel, red, green, blue;
 720     register CGFloat pixelFloat;
 721     register jint x, y;
 722 
 723     for (y=0; y<h; y++)
 724     {
 725         for (x=0; x<w; x++)
 726         {
 727             pixel        = *pixelsSrc;
 728 
 729             // gznote: do we remove alpha pre here?
 730             alpha        = ((pixel >> 24) & mask); //extract
 731 
 732             if (alpha != 0)
 733             {
 734                 red            = ((pixel >> 16) & mask); // extract
 735                 green        = ((pixel >> 8) & mask); // extract
 736                 blue        = ((pixel >> 0) & mask); // extract
 737 
 738                 alpha        *= 0xff; // upsample to 16bit
 739                 red            *= 0xff; // upsample to 16bit
 740                 green        *= 0xff; // upsample to 16bit
 741                 blue        *= 0xff; // upsample to 16bit
 742 
 743                 red            = ((red * 0xffff) + 0x7fff) / alpha; // remove alpha pre
 744                 red            = (red <= 0xffff) ? red : 0xffff;
 745                 green        = ((green * 0xffff) + 0x7fff) / alpha; // remove alpha pre
 746                 green        = (green <= 0xffff) ? green : 0xffff;
 747                 blue        = ((blue * 0xffff) + 0x7fff) / alpha; // remove alpha pre
 748                 blue        = (blue <= 0xffff) ? blue : 0xffff;
 749 
 750                 pixelFloat    = red*0.3f + green*0.59f + blue*0.11f; // rgb->gray NTSC conversion
 751             }
 752             else
 753             {
 754                 pixelFloat = 0;
 755             }
 756 
 757             *pixelsDst    = (jint)pixelFloat;
 758             pixelsDst++;
 759 
 760             pixelsSrc++;
 761         }
 762 
 763         pixelsSrc += skipSrc;
 764         pixelsDst += skipDst;
 765     }
 766 }
 767 
 768 // 1. first "dither" the true color down by creating a 16 bit value of the real color that will serve as an index into the cache of indexes
 769 // 2. if the cache has a valid entry use it otherwise go through 3 and 4
 770 // 3. go through the color table and calculate Euclidian distance between the true color and the indexed colors
 771 // 4. map the shortest distance into the one and true index color and stick it into the dst (and cache)
 772 IMAGE_SURFACE_INLINE UInt16* copyARGB_PRE_bitToIndexed_8bit(jint w, jint h, jint nativePixelsBytesPerRow, Pixel32bit *pixelsSrc, jint javaPixelsBytesPerRow, jint javaPixelBytes, Pixel8bit *pixelsDst, Pixel32bit* lutdata, UInt32 lutDataSize, UInt16 *indexedColorTable)
 773 {
 774 PRINT("    copyARGB_PRE_bitToIndexed_8bit")
 775     static const UInt32 mask            = 0x000000ff;
 776 
 777     static const UInt32 indexSize        = 65536;        // 2^16 - 16 bits of precision
 778     static const UInt32 indexMask        = 0x000000f0;    // 00000000000000000000000011110000
 779     static const UInt16 invalidIndex    = 0xffff;        // 1111111111111111
 780 
 781     register jint skipSrc = (nativePixelsBytesPerRow/sizeof(Pixel32bit))-w; // in pixelsSrc units
 782     register jint skipDst = (javaPixelsBytesPerRow/javaPixelBytes)-w; // in pixelsSrc units
 783     register jint indexOfBest, indexOfBestCached = -1;
 784     register CGFloat distanceOfBest, distance;
 785     register UInt32 p1, p1Cached = 0, p1a, p1r, p1g, p1b, p2;
 786     register SInt32 da, dr, dg, db;
 787     register jint x, y, i;
 788     BOOL cachedValueReady = NO;
 789 
 790     if (indexedColorTable == NULL)
 791     {
 792         indexedColorTable = (UInt16*)malloc(indexSize*sizeof(UInt16));    // 15 bit precision, each entry capable of holding a 2 byte value
 793                                                                         // (lower byte for the actual index, higher byte to mark it valid/invalid)
 794 
 795         if (indexedColorTable != NULL)
 796         {
 797             memset((void*)indexedColorTable, invalidIndex, indexSize*sizeof(UInt16));
 798         }
 799         else
 800         {
 801             fprintf(stderr, "ERROR: malloc returns NULL for isdo->indexedColorTable in copyARGB_PRE_bitToIndexed_8bit");
 802             return NULL;
 803         }
 804     }
 805 
 806     register UInt16 cacheIndex;
 807 
 808     for (y=0; y<h; y++)
 809     {
 810         for (x=0; x<w; x++)
 811         {
 812             p1 = *pixelsSrc;
 813 
 814             if ((p1Cached != p1) || (cachedValueReady == NO))
 815             {
 816                 p1a = ((p1 >> 24) & mask);
 817 
 818                 if (p1a != 0)
 819                 {
 820                     // extract color components
 821                     p1r = ((p1 >> 16) & mask);
 822                     p1g = ((p1 >> 8) & mask);
 823                     p1b = ((p1 >> 0) & mask);
 824 
 825                     // remove alpha pre
 826                     p1r = ((p1r * 0xff) + 0x7f) / p1a;
 827                     p1g = ((p1g * 0xff) + 0x7f) / p1a;
 828                     p1b = ((p1b * 0xff) + 0x7f) / p1a;
 829 
 830                     // clamp
 831                     p1r = (p1r <= 0xff) ? p1r : 0xff;
 832                     p1g = (p1g <= 0xff) ? p1g : 0xff;
 833                     p1b = (p1b <= 0xff) ? p1b : 0xff;
 834                 }
 835                 else
 836                 {
 837                     p1r = 0;
 838                     p1g = 0;
 839                     p1b = 0;
 840                 }
 841 
 842                 cacheIndex = (UInt16)(((p1a & indexMask) << 8) | ((p1r & indexMask) << 4) | ((p1g & indexMask) << 0) | ((p1b & indexMask) >> 4));
 843                 if (indexedColorTable[cacheIndex] == invalidIndex)
 844                 {
 845                     indexOfBest = 0;
 846                     distanceOfBest = DBL_MAX;
 847 
 848                     for (i=0; (unsigned)i<lutDataSize; i++)
 849                     {
 850                         p2 = lutdata[i];
 851 
 852                         da = p1a - ((p2 >> 24) & mask);
 853                         dr = p1r - ((p2 >> 16) & mask);
 854                         dg = p1g - ((p2 >> 8) & mask);
 855                         db = p1b - ((p2 >> 0) & mask);
 856 
 857                         distance = sqrt((da*da)+(dr*dr)+(dg*dg)+(db*db));
 858                         if (distance < distanceOfBest)
 859                         {
 860                             distanceOfBest = distance;
 861                             indexOfBest = i;
 862                         }
 863                     }
 864 
 865                     indexedColorTable[cacheIndex] = indexOfBest;
 866                 }
 867                 else
 868                 {
 869                     indexOfBest = indexedColorTable[cacheIndex];
 870                 }
 871 
 872                 cachedValueReady = YES;
 873                 p1Cached = p1;
 874                 indexOfBestCached = indexOfBest;
 875             }
 876             else
 877             {
 878                 indexOfBest = indexOfBestCached;
 879             }
 880 
 881             *pixelsDst = indexOfBest;
 882 
 883             pixelsDst++;
 884             pixelsSrc++;
 885         }
 886         pixelsSrc += skipSrc;
 887         pixelsDst += skipDst;
 888     }
 889 
 890     return indexedColorTable;
 891 }
 892 
 893 // callback from CG telling us it's done with the data. <rdar://problem/4762033>
 894 static void releaseDataFromProvider(void *info, const void *data, size_t size)
 895 {
 896     if (data != NULL)
 897     {
 898         free((void*)data);
 899     }
 900 }
 901 
 902 IMAGE_SURFACE_INLINE void createContext(JNIEnv *env, ImageSDOps *isdo)
 903 {
 904 PRINT("createContext")
 905 
 906     QuartzSDOps *qsdo = (QuartzSDOps*)isdo;
 907     if (qsdo->cgRef == NULL)  // lazy creation
 908     {
 909         size_t bitsPerComponent = isdo->contextInfo.bitsPerComponent;
 910         CGColorSpaceRef colorSpace = isdo->contextInfo.colorSpace;
 911         CGImageAlphaInfo alphaInfo = isdo->contextInfo.alphaInfo;
 912 
 913         size_t bytesPerRow = isdo->contextInfo.bytesPerRow;
 914         size_t size = bytesPerRow * isdo->height;
 915         isdo->nativePixels = malloc(size);
 916 
 917         if (isdo->nativePixels == NULL)
 918         {
 919             fprintf(stderr, "malloc failed for size %d bytes in ImageSurfaceData.createContext()\n", (int) size);
 920         }
 921 
 922 //fprintf(stderr, "isdo=%p isdo->type=%d, bitsPerComponent=%d, bytesPerRow=%d, colorSpace=%p, alphaInfo=%d, width=%d, height=%d, size=%d\n", isdo, type, (jint)bitsPerComponent, (jint)bytesPerRow, colorSpace, (jint)alphaInfo, (jint) isdo->width, (jint) isdo->height, (jint) size);
 923 
 924         qsdo->cgRef = CGBitmapContextCreate(isdo->nativePixels, isdo->width, isdo->height, bitsPerComponent, bytesPerRow, colorSpace, alphaInfo);
 925         isdo->dataProvider = CGDataProviderCreateWithData(NULL, isdo->nativePixels, size, releaseDataFromProvider);
 926     }
 927 
 928 //fprintf(stderr, "cgRef=%p\n", qsdo->cgRef);
 929     if (qsdo->cgRef == NULL)
 930     {
 931         fprintf(stderr, "ERROR: (qsdo->cgRef == NULL) in createContext!\n");
 932     }
 933 
 934     // intitalize the context to match the Java coordinate system
 935 
 936     // BG, since the context is created above, we can just concat
 937     CGContextConcatCTM(qsdo->cgRef, CGAffineTransformMake(1, 0, 0, -1, 0, isdo->height));
 938 
 939     CGContextSaveGState(qsdo->cgRef); // this will make sure we don't go pass device context settings
 940     CGContextSaveGState(qsdo->cgRef); // this will put user settings on top, used by LazyStateManagement code
 941     qsdo->newContext = YES;
 942 }
 943 
 944 IMAGE_SURFACE_INLINE void holdJavaPixels(JNIEnv* env, ImageSDOps* isdo)
 945 {
 946 PRINT("holdJavaPixels")
 947 
 948     if (isdo->type != java_awt_image_BufferedImage_TYPE_CUSTOM)
 949     {
 950         Pixel8bit* pixels = NULL;
 951         if (isdo->nrOfPixelsOwners == 0)
 952         {
 953             pixels = (Pixel8bit*)((*env)->GetPrimitiveArrayCritical(env, isdo->array, NULL));
 954             if (pixels != NULL)
 955             {
 956                 isdo->pixelsLocked = pixels;
 957 
 958                 isdo->pixels = isdo->pixelsLocked + isdo->offset;
 959             }
 960             else
 961             {
 962                 fprintf(stderr, "ERROR: GetPrimitiveArrayCritical returns NULL for pixels in holdJavaPixels!\n");
 963             }
 964         }
 965         isdo->nrOfPixelsOwners++;
 966     }
 967     else if (isdo->pixels == NULL)
 968     {
 969         isdo->pixels = (Pixel8bit*)((*env)->GetDirectBufferAddress(env, isdo->array));
 970     }
 971 }
 972 
 973 IMAGE_SURFACE_INLINE void unholdJavaPixels(JNIEnv* env, ImageSDOps* isdo)
 974 {
 975 PRINT("unholdJavaPixels")
 976 
 977     if (isdo->type != java_awt_image_BufferedImage_TYPE_CUSTOM)
 978     {
 979         isdo->nrOfPixelsOwners--;
 980         if (isdo->nrOfPixelsOwners == 0)
 981         {
 982             isdo->pixels = NULL;
 983 
 984             (*env)->ReleasePrimitiveArrayCritical(env, isdo->array, isdo->pixelsLocked, 0); // Do not use JNI_COMMIT, as that will not free the buffer copy when +ProtectJavaHeap is on.
 985             isdo->pixelsLocked = NULL;
 986         }
 987     }
 988 }
 989 
 990 static void imageDataProvider_UnholdJavaPixels(void *info, const void *data, size_t size)
 991 {
 992 PRINT("imageDataProvider_UnholdJavaPixels")
 993 
 994     // Currently do nothing
 995 }
 996 
 997 static void imageDataProvider_FreeTempPixels(void *info, const void *data, size_t size)
 998 {
 999 PRINT("imageDataProvider_FreeTempPixels")
1000 
1001     free((void *)data);
1002 }
1003 IMAGE_SURFACE_INLINE void syncFromJavaPixels(JNIEnv* env, ImageSDOps* isdo)
1004 {
1005 PRINT("syncFromJavaPixels")
1006 
1007     // check to see if we have any work to do
1008     if (isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] == 1)
1009     {
1010         // if we do, lock down Java pixels, this halts GarbageCollector!
1011         holdJavaPixels(env, isdo);
1012         if (isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] == 1)
1013         {
1014             isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] = 0;
1015 
1016             void *dataProviderData = NULL;
1017             void *dataProviderInfo = NULL;
1018             void *dataProviderCallback = NULL;
1019             size_t dataProviderDataSize = 0;
1020             size_t width = isdo->width;
1021             size_t height = isdo->height;
1022             size_t bitsPerComponent = isdo->imageInfo.bitsPerComponent;
1023             size_t bitsPerPixel = isdo->imageInfo.bitsPerPixel;
1024             size_t bytesPerRow = 0;
1025             size_t extraBytesPerRow = 0; // these are the extra bytesPerRow used for alignement
1026 
1027             switch (isdo->type)
1028             {
1029                 //case java_awt_image_BufferedImage_TYPE_BYTE_BINARY: // mapped to TYPE_CUSTOM
1030                 case java_awt_image_BufferedImage_TYPE_CUSTOM:
1031                     holdJavaPixels(env, isdo);    // we lock again since we are reusing pixels, but we must ensure CGImageRef immutability
1032                                                 // we can lock these pixels down because they are nio based, so we don't halt the GarbageCollector
1033                     bytesPerRow = isdo->javaPixelsBytesPerRow;
1034                     dataProviderDataSize = bytesPerRow*isdo->height;
1035                     dataProviderData = isdo->pixels;
1036                     dataProviderInfo = isdo;
1037                     dataProviderCallback = imageDataProvider_UnholdJavaPixels;
1038                     break;
1039                 default:
1040                     bytesPerRow = isdo->imageInfo.bytesPerRow;
1041                     dataProviderDataSize = bytesPerRow*height;
1042                     dataProviderData = malloc(dataProviderDataSize);
1043                     dataProviderInfo = isdo;
1044                     dataProviderCallback = imageDataProvider_FreeTempPixels;
1045             }
1046 
1047             switch (isdo->type)
1048             {
1049                 //case java_awt_image_BufferedImage_TYPE_BYTE_BINARY: // mapped to TYPE_CUSTOM
1050                 case java_awt_image_BufferedImage_TYPE_CUSTOM:
1051                     customPixelsFromJava(env, isdo);
1052                     break;
1053                 case java_awt_image_BufferedImage_TYPE_INT_RGB:
1054                 case java_awt_image_BufferedImage_TYPE_INT_ARGB:
1055                 case java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE:
1056                 case java_awt_image_BufferedImage_TYPE_USHORT_555_RGB:
1057                 case java_awt_image_BufferedImage_TYPE_USHORT_GRAY:
1058                 case java_awt_image_BufferedImage_TYPE_BYTE_GRAY:
1059                     copyBits(width, height, isdo->javaPixelsBytesPerRow, (Pixel8bit*)isdo->pixels, bytesPerRow, dataProviderData);
1060                     break;
1061                 case java_awt_image_BufferedImage_TYPE_INT_BGR:
1062                     copySwapRandB_32bit_TYPE_INT(width, height, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, (Pixel32bit*)isdo->pixels, dataProviderData, extraBytesPerRow);
1063                     break;
1064                 case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR:
1065                 case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE:
1066                     copySwapRandB_32bit_TYPE_4BYTE(width, height, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, (Pixel32bit*)isdo->pixels, dataProviderData, extraBytesPerRow);
1067                     break;
1068                 case java_awt_image_BufferedImage_TYPE_3BYTE_BGR:
1069                     copyBGR_24bitToXRGB_32bit(width, height, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, isdo->pixels, dataProviderData, extraBytesPerRow);
1070                     break;
1071                 case sun_java2d_OSXOffScreenSurfaceData_TYPE_3BYTE_RGB:
1072                     copyRGB_24bitToXRGB_32bit(width, height, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, isdo->pixels, dataProviderData, extraBytesPerRow);
1073                     break;
1074                 case java_awt_image_BufferedImage_TYPE_USHORT_565_RGB:
1075                     copy565_16bitTo555_16bit(width, height, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, (Pixel16bit*)isdo->pixels, dataProviderData, extraBytesPerRow);
1076                     break;
1077                 case java_awt_image_BufferedImage_TYPE_BYTE_INDEXED:
1078                     copyIndexed_8bitToARGB_32bit(width, height, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, isdo->pixels, isdo->lutData, dataProviderData, extraBytesPerRow);
1079                     break;
1080                 default:
1081                     break;
1082             }
1083 
1084             CGDataProviderRef provider = CGDataProviderCreateWithData(dataProviderInfo, dataProviderData, dataProviderDataSize, dataProviderCallback);
1085             CGImageRef javaImg = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow,
1086                                                 isdo->imageInfo.colorSpace, isdo->imageInfo.alphaInfo, provider, NULL, NO, kCGRenderingIntentDefault);
1087 //fprintf(stderr, "javaImg=%p\n", javaImg);
1088             CGDataProviderRelease(provider);
1089 
1090             if (javaImg != NULL)
1091             {
1092                 QuartzSDOps *qsdo = (QuartzSDOps*)isdo;
1093 
1094                 if (isdo->imgRef != NULL)
1095                 {
1096                     CGImageRelease(isdo->imgRef);
1097                     isdo->imgRef = NULL;
1098                 }
1099 
1100                 if (qsdo->cgRef == NULL)
1101                 {
1102                     createContext(env, isdo);
1103                 }
1104 
1105                 if (qsdo->cgRef != NULL)
1106                 {
1107                     CGContextSaveGState(qsdo->cgRef);
1108                     CGAffineTransform currCTM = CGContextGetCTM(qsdo->cgRef);
1109                     CGAffineTransform inverse = CGAffineTransformInvert(currCTM);
1110                     CGContextConcatCTM(qsdo->cgRef, inverse);
1111                     CGContextConcatCTM(qsdo->cgRef, CGAffineTransformMake(1, 0, 0, 1, 0, 0));
1112                     CGContextSetBlendMode(qsdo->cgRef, kCGBlendModeCopy);
1113                     CGContextSetAlpha(qsdo->cgRef, 1.0f);
1114                     CGContextDrawImage(qsdo->cgRef, CGRectMake(0, 0, width, height), javaImg);
1115                     CGContextFlush(qsdo->cgRef);
1116                     CGContextRestoreGState(qsdo->cgRef);
1117                     CGImageRelease(javaImg);
1118                 }
1119                 else
1120                 {
1121                     fprintf(stderr, "ERROR: (cgRef == NULL) in syncFromJavaPixels!\n");
1122                 }
1123             }
1124             else
1125             {
1126 //fprintf(stderr, "isdo->type=%d, isdo->width=%d, isdo->height=%d, isdo->imageInfo.bitsPerComponent=%d, isdo->imageInfo.bytesPerPixel=%d, isdo->imageInfo.bitsPerPixel=%d, isdo->imageInfo.bytesPerRow=%d, isdo->imageInfo.colorSpace=%p, isdo->imageInfo.alphaInfo=%d\n",
1127 //(jint)isdo->type, (jint)isdo->width, (jint)isdo->height, (jint)isdo->imageInfo.bitsPerComponent, (jint)isdo->imageInfo.bytesPerPixel, (jint)isdo->imageInfo.bitsPerPixel, (jint)isdo->imageInfo.bytesPerRow, isdo->imageInfo.colorSpace, (jint)isdo->imageInfo.alphaInfo);
1128                 fprintf(stderr, "ERROR: (javaImg == NULL) in syncFromJavaPixels!\n");
1129             }
1130         }
1131 
1132         unholdJavaPixels(env, isdo);
1133     }
1134 }
1135 
1136 IMAGE_SURFACE_INLINE void processPixels(ImageSDOps* isdo, jint x, jint y, jint width, jint height, void (*processPixelsCallback) (ImageSDOps *, jint, Pixel32bit *, jint, jint, jint, jint))
1137 {
1138     processPixelsCallback(isdo, (jint) isdo->contextInfo.bytesPerRow, (Pixel32bit *) isdo->nativePixels, x, y, width, height);
1139 }
1140 
1141 IMAGE_SURFACE_INLINE void syncToJavaPixels_processPixelsCallback(ImageSDOps* isdo, jint nativePixelsBytesPerRow, Pixel32bit *dataSrc, jint x, jint y, jint width, jint height)
1142 {
1143     switch (isdo->type)
1144     {
1145         case java_awt_image_BufferedImage_TYPE_3BYTE_BGR:
1146             copyARGB_PRE_32bitToBGR_24bit(isdo->width, isdo->height, nativePixelsBytesPerRow, dataSrc, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, isdo->pixels);
1147             break;
1148         case sun_java2d_OSXOffScreenSurfaceData_TYPE_3BYTE_RGB:
1149             copyARGB_PRE_32bitToRGB_24bit(isdo->width, isdo->height, nativePixelsBytesPerRow, dataSrc, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, isdo->pixels);
1150             break;
1151         case java_awt_image_BufferedImage_TYPE_USHORT_GRAY:
1152             copyARGB_PRE_32bitToGray_16bit(isdo->width, isdo->height, nativePixelsBytesPerRow, dataSrc, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, (Pixel16bit*)isdo->pixels);
1153             break;
1154         case java_awt_image_BufferedImage_TYPE_BYTE_INDEXED:
1155             isdo->indexedColorTable = copyARGB_PRE_bitToIndexed_8bit(isdo->width, isdo->height, nativePixelsBytesPerRow, dataSrc, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, isdo->pixels, isdo->lutData, isdo->lutDataSize, isdo->indexedColorTable);
1156             break;
1157         default:
1158             break;
1159     }
1160 }
1161 
1162 
1163 IMAGE_SURFACE_INLINE void syncToJavaPixels(JNIEnv* env, ImageSDOps* isdo)
1164 {
1165 PRINT("syncToJavaPixels")
1166 
1167     holdJavaPixels(env, isdo);
1168 
1169     QuartzSDOps *qsdo = (QuartzSDOps*)isdo;
1170     if (qsdo->cgRef == NULL)
1171     {
1172         createContext(env, isdo);
1173     }
1174 
1175     isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNativePixelsChangedIndex] = 0;
1176 
1177     if (isdo->contextInfo.canUseJavaPixelsAsContext == YES)
1178     {
1179 
1180         jint srcBytesPerRow = isdo->contextInfo.bytesPerRow;
1181         jint dstBytesPerRow = isdo->javaPixelsBytesPerRow;
1182         jint h = isdo->height;
1183         Pixel8bit *pixelsSrc = isdo->nativePixels;
1184         Pixel8bit *pixelsDst = isdo->pixels;
1185 
1186         if (srcBytesPerRow == dstBytesPerRow)
1187         {
1188             memcpy(pixelsDst, pixelsSrc, h * dstBytesPerRow);
1189         }
1190         else
1191         {
1192             jint widthInBytes = isdo->width * isdo->contextInfo.bytesPerPixel;
1193             jint y;
1194             for (y=0; y < h; y++)
1195             {
1196                 memcpy(pixelsDst, pixelsSrc, widthInBytes);
1197 
1198                 pixelsSrc += srcBytesPerRow;
1199                 pixelsDst += dstBytesPerRow;
1200             }
1201         }
1202 
1203         switch (isdo->type)
1204         {
1205             //case java_awt_image_BufferedImage_TYPE_BYTE_BINARY: // mapped to TYPE_CUSTOM
1206             case java_awt_image_BufferedImage_TYPE_CUSTOM:
1207                 customPixelsToJava(env, isdo);
1208                 break;
1209             case java_awt_image_BufferedImage_TYPE_INT_ARGB:
1210                 removeAlphaPre_32bit(isdo->width, isdo->height, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, (Pixel32bit*)isdo->pixels);
1211                 break;
1212             case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR:
1213                 swapRandBAndRemoveAlphaPre_32bit(isdo->width, isdo->height, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, (Pixel32bit*)isdo->pixels);
1214                 break;
1215             case java_awt_image_BufferedImage_TYPE_INT_BGR:
1216                 swapRandB_32bit_TYPE_INT(isdo->width, isdo->height, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, (Pixel32bit*)isdo->pixels);
1217                 break;
1218             case java_awt_image_BufferedImage_TYPE_4BYTE_ABGR_PRE:
1219                 swapRandB_32bit_TYPE_4BYTE(isdo->width, isdo->height, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, (Pixel32bit*)isdo->pixels);
1220                 break;
1221             case java_awt_image_BufferedImage_TYPE_USHORT_565_RGB:
1222                 map555_16bitTo565_16bit(isdo->width, isdo->height, isdo->javaPixelsBytesPerRow, isdo->javaPixelBytes, (Pixel16bit*)isdo->pixels);
1223                 break;
1224             default:
1225                 break;
1226         }
1227     }
1228     else
1229     {
1230         processPixels(isdo, 0, 0, isdo->width, isdo->height, &syncToJavaPixels_processPixelsCallback);
1231     }
1232 
1233     unholdJavaPixels(env, isdo);
1234 }
1235 
1236 
1237 IMAGE_SURFACE_INLINE jboolean xorSurfacePixels(JNIEnv *env, jobject dstIsd, jobject srcIsd, jint colorXOR, jint x, jint y, jint w, jint h)
1238 {
1239 PRINT("xorSurfacePixels")
1240 
1241     jboolean handled = JNI_FALSE;
1242 
1243 JNI_COCOA_ENTER(env);
1244     ImageSDOps* srcIsdo = LockImagePixels(env, srcIsd);
1245     ImageSDOps* dstIsdo = LockImagePixels(env, dstIsd);
1246 
1247     if ((x < 0) || (y < 0) || (x+w > dstIsdo->width) || (y+h > dstIsdo->height) || (w > srcIsdo->width) || (h > srcIsdo->height))
1248     {
1249 #ifdef PRINT_WARNINGS
1250 fprintf(stderr, "xorSurfacePixels INVALID parameters: x=%d, y=%d, w=%d, h=%d\n", x, y, w, h);
1251 fprintf(stderr, "   dstIsdo->width=%d, dstIsdo->height=%d, biqsdoPixels->width=%d, biqsdoPixels->height=%d\n",
1252                         dstIsdo->width, dstIsdo->height, srcIsdo->width, srcIsdo->height);
1253 #endif
1254         UnlockImagePixels(env, srcIsdo);
1255         UnlockImagePixels(env, dstIsdo);
1256 
1257         return JNI_FALSE;
1258     }
1259 
1260     jint offset = (dstIsdo->width*y)+x;
1261     register Pixel32bit* dstPixels = (Pixel32bit*)dstIsdo->pixels;
1262     register jint skip = dstIsdo->width - w;
1263     register Pixel32bit* srcPixels = (Pixel32bit*)srcIsdo->pixels;
1264     register jint skipPixels = srcIsdo->width - w;
1265     register jint i, j;
1266 
1267     dstPixels += offset;
1268 
1269     switch (dstIsdo->type)
1270     {
1271         case java_awt_image_BufferedImage_TYPE_INT_RGB:
1272         case java_awt_image_BufferedImage_TYPE_INT_ARGB:
1273         case java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE:
1274         {
1275             dstIsdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] = 1;
1276 
1277             if (dstIsdo->type == java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE)
1278             {
1279                 Pixel8bit alpha = (colorXOR>>24)&0xff;
1280                 Pixel8bit red = (colorXOR>>16)&0xff;
1281                 red = (jint)(((CGFloat)red/255.0f * (CGFloat)alpha/255.0f)*255.0f);
1282                 Pixel8bit green = (colorXOR>>8)&0xff;
1283                 green = (jint)(((CGFloat)green/255.0f * (CGFloat)alpha/255.0f)*255.0f);
1284                 Pixel8bit blue = (colorXOR>>0)&0xff;
1285                 blue = (jint)(((CGFloat)blue/255.0f * (CGFloat)alpha/255.0f)*255.0f);
1286                 colorXOR = (alpha<<24) | (red<<16) | (green<<8) | blue; // the color is now alpha premultiplied
1287             }
1288 
1289             for (i=0; i<h; i++)
1290             {
1291                 for (j=0; j<w; j++)
1292                 {
1293                     Pixel32bit srcPixel = *srcPixels;
1294                     Pixel8bit pixelAlpha = (srcPixel>>24);
1295                     if (pixelAlpha > XOR_ALPHA_CUTOFF)
1296                     {
1297                         *dstPixels = (*dstPixels ^ (srcPixel ^ colorXOR));
1298                     }
1299                     dstPixels++; srcPixels++;
1300                 }
1301 
1302                 dstPixels += skip;
1303                 srcPixels += skipPixels;
1304             }
1305 
1306             handled = JNI_TRUE;
1307             break;
1308         }
1309         default:
1310         {
1311             handled = JNI_FALSE;
1312 #if defined(PRINT_WARNINGS)
1313             fprintf(stderr, "WARNING: unknown type (%d) in compositeXOR\n", dstIsdo->type);
1314             PrintImageInfo(dstIsdo);
1315 #endif
1316         }
1317     }
1318 
1319     UnlockImagePixels(env, srcIsdo);
1320     UnlockImagePixels(env, dstIsdo);
1321 
1322 JNI_COCOA_EXIT(env);
1323     return handled;
1324 }
1325 
1326 IMAGE_SURFACE_INLINE jboolean clearSurfacePixels(JNIEnv *env, jobject bisd, jint w, jint h)
1327 {
1328 PRINT("clearSurfacePixels")
1329     jboolean handled = JNI_FALSE;
1330 
1331 JNI_COCOA_ENTER(env);
1332 
1333     ImageSDOps *isdo = LockImagePixels(env, bisd);
1334 
1335     if (isdo->type == java_awt_image_BufferedImage_TYPE_INT_ARGB_PRE)
1336     {
1337         isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] = 1;
1338 
1339         w = (w < isdo->width) ? w : isdo->width;
1340         h = (h < isdo->height) ? h : isdo->height;
1341 
1342         register Pixel32bit* data = (Pixel32bit*)isdo->pixels;
1343         register jint i;
1344         if ((w < isdo->width) || (h < isdo->height)) //cmcnote: necessary to special-case for small height? wouldn't 4*w*h do it?
1345         {
1346             register jint skip = isdo->width;
1347             register jint row = 4*w;
1348             for (i=0; i<h; i++)
1349             {
1350                 bzero(data, row);
1351                 data += skip;
1352             }
1353         }
1354         else
1355         {
1356             bzero(data, 4*w*h);
1357         }
1358 
1359         handled = JNI_TRUE;
1360     }
1361     UnlockImagePixels(env, isdo);
1362 
1363 JNI_COCOA_EXIT(env);
1364 
1365     return handled;
1366 }
1367 
1368 static void ImageSD_startCGContext(JNIEnv *env, QuartzSDOps *qsdo, SDRenderType renderType)
1369 {
1370 PRINT("ImageSD_startCGContext")
1371 
1372     ImageSDOps *isdo = (ImageSDOps*)qsdo;
1373 
1374     pthread_mutex_lock(&isdo->lock);
1375 
1376     if (isdo->imgRef != NULL)
1377     {
1378         CGImageRelease(isdo->imgRef);
1379         isdo->imgRef = NULL;
1380     }
1381 
1382     if (qsdo->cgRef == NULL)
1383     {
1384         createContext(env, isdo);
1385     }
1386     else
1387     {
1388         qsdo->newContext = NO;
1389     }
1390 
1391     if (qsdo->cgRef != NULL)
1392     {
1393         if (isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kImageStolenIndex] == 1)
1394         {
1395             isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] = 1;
1396         }
1397 
1398         // sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex can be set right above or somewhere else
1399         if (isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] == 1)
1400         {
1401             syncFromJavaPixels(env, isdo);
1402         }
1403 
1404         isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNativePixelsChangedIndex] = 1;
1405 
1406         SetUpCGContext(env, qsdo, renderType);
1407     }
1408 }
1409 static void ImageSD_finishCGContext(JNIEnv *env, QuartzSDOps *qsdo)
1410 {
1411 PRINT("ImageSD_finishCGContext")
1412 
1413     ImageSDOps *isdo = (ImageSDOps*)qsdo;
1414 
1415     if (qsdo->cgRef != NULL)
1416     {
1417         CompleteCGContext(env, qsdo);
1418 
1419         if (isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kImageStolenIndex] == 1)
1420         {
1421             syncToJavaPixels(env, isdo);
1422             isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] = 1;
1423         }
1424     }
1425 
1426     pthread_mutex_unlock(&isdo->lock);
1427 }
1428 
1429 static void ImageSD_dispose(JNIEnv *env, SurfaceDataOps *ops)
1430 {
1431 PRINT("ImageSD_dispose")
1432 
1433     // copied from BufImg_Dispose in BufImgSurfaceData.c
1434     {
1435         /* ops is assumed non-null as it is checked in SurfaceData_DisposeOps */
1436         BufImgSDOps *bisdo = (BufImgSDOps *)ops;
1437         (*env)->DeleteWeakGlobalRef(env, bisdo->array);
1438         if (bisdo->lutarray != NULL) {
1439         (*env)->DeleteWeakGlobalRef(env, bisdo->lutarray);
1440         }
1441         if (bisdo->icm != NULL) {
1442         (*env)->DeleteWeakGlobalRef(env, bisdo->icm);
1443         }
1444     }
1445 
1446     QuartzSDOps *qsdo = (QuartzSDOps *)ops;
1447 
1448     if (qsdo->graphicsStateInfo.batchedLines != NULL)
1449     {
1450         free(qsdo->graphicsStateInfo.batchedLines);
1451         qsdo->graphicsStateInfo.batchedLines = NULL;
1452     }
1453 
1454     (*env)->DeleteGlobalRef(env, qsdo->javaGraphicsStatesObjects);
1455 
1456     if (qsdo->cgRef != NULL)
1457     {
1458         CGContextRelease(qsdo->cgRef);
1459         qsdo->cgRef = NULL;
1460     }
1461 
1462     ImageSDOps *isdo = (ImageSDOps *)ops;
1463 
1464     if (isdo->dataProvider != NULL)
1465     {
1466         CGDataProviderRelease(isdo->dataProvider);
1467         isdo->dataProvider = NULL;
1468     }
1469     if (isdo->imgRef != NULL)
1470     {
1471         CGImageRelease(isdo->imgRef);
1472         isdo->imgRef = NULL;
1473     }
1474     if (isdo->indexedColorTable != NULL)
1475     {
1476         free(isdo->indexedColorTable);
1477         isdo->indexedColorTable = NULL;
1478     }
1479     if (isdo->lutData != NULL)
1480     {
1481         free(isdo->lutData);
1482         isdo->indexedColorTable = NULL;
1483     }
1484     if (isdo->array != NULL)
1485     {
1486         (*env)->DeleteGlobalRef(env, isdo->array);
1487         isdo->array = NULL;
1488     }
1489     if (isdo->icm != NULL)
1490     {
1491         (*env)->DeleteGlobalRef(env, isdo->icm);
1492         isdo->icm = NULL;
1493     }
1494 
1495     if (isdo->nsRef) {
1496         [isdo->nsRef release];
1497         isdo->nsRef = nil;
1498     }
1499 
1500     pthread_mutex_destroy(&isdo->lock);
1501 }
1502 
1503 // used by XOR (Java pixels must be up to date)
1504 ImageSDOps* LockImagePixels(JNIEnv* env, jobject imageSurfaceData)
1505 {
1506 PRINT("LockImagePixels")
1507 
1508     ImageSDOps* isdo = (ImageSDOps*)SurfaceData_GetOps(env, imageSurfaceData);
1509 
1510     pthread_mutex_lock(&isdo->lock);
1511 
1512     holdJavaPixels(env, isdo);
1513 
1514     // if we need to access this image's pixels we need to convert native pixels (if any) back to Java
1515     if (isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNativePixelsChangedIndex] == 1)
1516     {
1517         syncToJavaPixels(env, isdo);
1518         isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] = 1;
1519     }
1520 
1521     return isdo;
1522 }
1523 void UnlockImagePixels(JNIEnv* env, ImageSDOps* isdo)
1524 {
1525 PRINT("UnlockImagePixels")
1526     // don't do that since the native pixels haven't changed (Java pixels == native pixels)
1527     //syncToJavaPixels(env, isdo);
1528 
1529     unholdJavaPixels(env, isdo);
1530 
1531     pthread_mutex_unlock(&isdo->lock);
1532 }
1533 
1534 // used by drawImage (native pixels must be up to date)
1535 ImageSDOps* LockImage(JNIEnv* env, jobject imageSurfaceData)
1536 {
1537 PRINT("LockImage")
1538 
1539     ImageSDOps* isdo = (ImageSDOps*)SurfaceData_GetOps(env, imageSurfaceData);
1540 
1541     pthread_mutex_lock(&isdo->lock);
1542 
1543     // if we need to access this image's pixels we need to convert native pixels (if any) back to Java
1544     // for those images whose context type doesn't match layer type or is a custom image
1545     if (isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kImageStolenIndex] == 1)
1546     {
1547         isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] = 1;
1548     }
1549 
1550     // sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex can be set right above or somewhere else
1551     if (isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] == 1)
1552     {
1553         syncFromJavaPixels(env, isdo);
1554     }
1555 
1556     return isdo;
1557 }
1558 void UnlockImage(JNIEnv* env, ImageSDOps* isdo)
1559 {
1560 PRINT("UnlockImage")
1561 
1562     // don't do that since the native pixels haven't changed (Java pixels == native pixels)
1563     //syncToJavaPixels(env, isdo);
1564 
1565     pthread_mutex_unlock(&isdo->lock);
1566 }
1567 
1568 JNIEXPORT jobject JNICALL Java_sun_awt_image_BufImgSurfaceData_getSurfaceData
1569     (JNIEnv *env, jclass bisd, jobject bufImg)
1570 {
1571     static jfieldID sDataID = 0;
1572     if (sDataID == 0)
1573     {
1574         static char *bimgName = "java/awt/image/BufferedImage";
1575         jclass bimg = (*env)->FindClass(env, bimgName);
1576         CHECK_NULL_RETURN(bimg, NULL);
1577         sDataID = (*env)->GetFieldID(env, bimg, "sData", "Lsun/java2d/SurfaceData;");
1578         CHECK_NULL_RETURN(sDataID, NULL);
1579     }
1580 
1581     return (*env)->GetObjectField(env, bufImg, sDataID);
1582 }
1583 
1584 JNIEXPORT void JNICALL Java_sun_awt_image_BufImgSurfaceData_setSurfaceData
1585     (JNIEnv *env, jclass bisd, jobject bufImg, jobject sData)
1586 {
1587     static jfieldID sDataID = 0;
1588     if (sDataID == 0)
1589     {
1590         static char *bimgName = "java/awt/image/BufferedImage";
1591         jclass bimg = (*env)->FindClass(env, bimgName);
1592         CHECK_NULL(bimg);
1593         sDataID = (*env)->GetFieldID(env, bimg, "sData", "Lsun/java2d/SurfaceData;");
1594         CHECK_NULL(sDataID);
1595     }
1596 
1597     (*env)->SetObjectField(env, bufImg, sDataID, sData);
1598 }
1599 
1600 JNIEXPORT void JNICALL Java_sun_java2d_OSXOffScreenSurfaceData_initIDs(JNIEnv *env, jclass bisd)
1601 {
1602 //PRINT("initIDs")
1603     // copied from Java_sun_awt_image_BufImgSurfaceData_initIDs in BufImgSurfaceData.c
1604     {
1605         static char *icmName = "java/awt/image/IndexColorModel";
1606         jclass icm;
1607 
1608         if (sizeof(BufImgRIPrivate) > SD_RASINFO_PRIVATE_SIZE) {
1609         JNU_ThrowInternalError(env, "Private RasInfo structure too large!");
1610         return;
1611         }
1612 
1613         CHECK_NULL(icm = (*env)->FindClass(env, icmName));
1614         CHECK_NULL(rgbID = (*env)->GetFieldID(env, icm, "rgb", "[I"));
1615         CHECK_NULL(allGrayID = (*env)->GetFieldID(env, icm, "allgrayopaque", "Z"));
1616         CHECK_NULL(mapSizeID = (*env)->GetFieldID(env, icm, "map_size", "I"));
1617         CHECK_NULL(CMpDataID = (*env)->GetFieldID(env, icm, "pData", "J"));
1618     }
1619 
1620     gColorspaceRGB = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
1621     gColorspaceGray = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
1622 //fprintf(stderr, "gColorspaceRGB=%p, gColorspaceGray=%p\n", gColorspaceRGB, gColorspaceGray);
1623 }
1624 
1625 static jclass jc_BufferedImage = NULL;
1626 static jfieldID jm_SurfaceData = NULL;
1627 
1628 JNIEXPORT jobject JNICALL Java_sun_java2d_OSXOffScreenSurfaceData_getSurfaceData
1629     (JNIEnv *env, jclass bisd, jobject bufImg)
1630 {
1631 PRINT("getSurfaceData")
1632     GET_CLASS_RETURN(jc_BufferedImage, "java/awt/image/BufferedImage", NULL);
1633     GET_FIELD_RETURN(jm_SurfaceData, jc_BufferedImage, "sData", "Lsun/java2d/SurfaceData;", NULL);
1634     return (*env)->GetObjectField(env, bufImg, jm_SurfaceData);
1635 }
1636 
1637 JNIEXPORT void JNICALL Java_sun_java2d_OSXOffScreenSurfaceData_setSurfaceData
1638     (JNIEnv *env, jclass bisd, jobject bufImg, jobject sData)
1639 {
1640 PRINT("setSurfaceData")
1641 
1642     GET_CLASS(jc_BufferedImage, "java/awt/image/BufferedImage");
1643     GET_FIELD(jm_SurfaceData, jc_BufferedImage, "sData", "Lsun/java2d/SurfaceData;");
1644     (*env)->SetObjectField(env, bufImg, jm_SurfaceData, sData);
1645 }
1646 
1647 static jint ImageSD_Lock(JNIEnv *env, SurfaceDataOps *ops, SurfaceDataRasInfo *pRasInfo, jint lockflags)
1648 {
1649     ImageSDOps *isdo = (ImageSDOps*)ops;
1650     pthread_mutex_lock(&isdo->lock);
1651 
1652     // copied from BufImg_Lock in BufImgSurfaceData.c
1653     {
1654         BufImgSDOps *bisdo = (BufImgSDOps *)ops;
1655         BufImgRIPrivate *bipriv = (BufImgRIPrivate *) &(pRasInfo->priv);
1656 
1657         if ((lockflags & (SD_LOCK_LUT)) != 0 && !bisdo->lutarray) {
1658             /* REMIND: Should this be an InvalidPipe exception? */
1659             JNU_ThrowNullPointerException(env, "Attempt to lock missing colormap");
1660             return SD_FAILURE;
1661         }
1662 // TODO:BG
1663         /*
1664         if ((lockflags & SD_LOCK_INVCOLOR) != 0 ||
1665             (lockflags & SD_LOCK_INVGRAY) != 0)
1666         {
1667             bipriv->cData = BufImg_SetupICM(env, bisdo);
1668             if (bipriv->cData == NULL) {
1669                 JNU_ThrowNullPointerException(env, "Could not initialize "
1670                                               "inverse tables");
1671                 return SD_FAILURE;
1672             }
1673         } else {
1674             bipriv->cData = NULL;
1675         }
1676         */
1677         bipriv->cData = NULL;
1678 
1679         bipriv->lockFlags = lockflags;
1680         bipriv->base = NULL;
1681         bipriv->lutbase = NULL;
1682 
1683         SurfaceData_IntersectBounds(&pRasInfo->bounds, &bisdo->rasbounds);
1684 
1685         /* TODO:BG
1686         if ((bipriv->lockFlags & SD_LOCK_WRITE) &&
1687             bisdo->sdOps.dirty != TRUE) {
1688             SurfaceData_MarkDirty(env, &bisdo->sdOps);
1689         } */
1690         return SD_SUCCESS;
1691     }
1692 }
1693 static void ImageSD_Unlock(JNIEnv *env, SurfaceDataOps *ops, SurfaceDataRasInfo *pRasInfo)
1694 {
1695     ImageSDOps *isdo = (ImageSDOps*)ops;
1696 
1697     // For every ImageSD_Unlock, we need to be conservative and mark the pixels
1698     // as modified by the Sun2D renderer.
1699     isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kNeedToSyncFromJavaPixelsIndex] = 1;
1700 
1701     pthread_mutex_unlock(&isdo->lock);
1702 }
1703 static void ImageSD_GetRasInfo(JNIEnv *env, SurfaceDataOps *ops, SurfaceDataRasInfo *pRasInfo)
1704 {
1705     // copied from BufImg_GetRasInfo in BufImgSurfaceData.c
1706     {
1707         BufImgSDOps *bisdo = (BufImgSDOps *)ops;
1708         BufImgRIPrivate *bipriv = (BufImgRIPrivate *) &(pRasInfo->priv);
1709 
1710         if ((bipriv->lockFlags & (SD_LOCK_RD_WR)) != 0) {
1711             bipriv->base =
1712                 (*env)->GetPrimitiveArrayCritical(env, bisdo->array, NULL);
1713         }
1714         if ((bipriv->lockFlags & (SD_LOCK_LUT)) != 0) {
1715             bipriv->lutbase =
1716                 (*env)->GetPrimitiveArrayCritical(env, bisdo->lutarray, NULL);
1717         }
1718 
1719         if (bipriv->base == NULL) {
1720             pRasInfo->rasBase = NULL;
1721             pRasInfo->pixelStride = 0;
1722             pRasInfo->scanStride = 0;
1723         } else {
1724             pRasInfo->rasBase = (void *)
1725                 (((uintptr_t) bipriv->base) + bisdo->offset);
1726             pRasInfo->pixelStride = bisdo->pixStr;
1727             pRasInfo->scanStride = bisdo->scanStr;
1728         }
1729         if (bipriv->lutbase == NULL) {
1730             pRasInfo->lutBase = NULL;
1731             pRasInfo->lutSize = 0;
1732         } else {
1733             pRasInfo->lutBase = bipriv->lutbase;
1734             pRasInfo->lutSize = bisdo->lutsize;
1735         }
1736         if (bipriv->cData == NULL) {
1737             pRasInfo->invColorTable = NULL;
1738             pRasInfo->redErrTable = NULL;
1739             pRasInfo->grnErrTable = NULL;
1740             pRasInfo->bluErrTable = NULL;
1741         } else {
1742             pRasInfo->invColorTable = bipriv->cData->img_clr_tbl;
1743             pRasInfo->redErrTable = bipriv->cData->img_oda_red;
1744             pRasInfo->grnErrTable = bipriv->cData->img_oda_green;
1745             pRasInfo->bluErrTable = bipriv->cData->img_oda_blue;
1746             pRasInfo->invGrayTable = bipriv->cData->pGrayInverseLutData;
1747         }
1748     }
1749 }
1750 static void ImageSD_Release(JNIEnv *env, SurfaceDataOps *ops, SurfaceDataRasInfo *pRasInfo)
1751 {
1752     // copied from BufImg_Release in BufImgSurfaceData.c
1753     {
1754         BufImgSDOps *bisdo = (BufImgSDOps *)ops;
1755         BufImgRIPrivate *bipriv = (BufImgRIPrivate *) &(pRasInfo->priv);
1756 
1757         if (bipriv->base != NULL) {
1758             jint mode = (((bipriv->lockFlags & (SD_LOCK_WRITE)) != 0)
1759                          ? 0 : JNI_ABORT);
1760             (*env)->ReleasePrimitiveArrayCritical(env, bisdo->array,
1761                                                   bipriv->base, mode);
1762         }
1763         if (bipriv->lutbase != NULL) {
1764             (*env)->ReleasePrimitiveArrayCritical(env, bisdo->lutarray,
1765                                                   bipriv->lutbase, JNI_ABORT);
1766         }
1767     }
1768 }
1769 
1770 JNIEXPORT void JNICALL Java_sun_java2d_OSXOffScreenSurfaceData_initRaster(JNIEnv *env, jobject bisd, jobject array, jint offset, jint width, jint height,
1771                                                                                 jint pixelStride, jint scanStride, jobject icm, jint type,
1772                                                                                     jobject jGraphicsState, jobjectArray jGraphicsStateObject, jobject jImageInfo)
1773 {
1774 PRINT("Java_sun_java2d_OSXOffScreenSurfaceData_initRaster")
1775 
1776     ImageSDOps* isdo = (ImageSDOps*)SurfaceData_InitOps(env, bisd, sizeof(ImageSDOps));
1777     if (isdo == NULL) {
1778         JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed.");
1779         return;
1780     }
1781 
1782     pthread_mutexattr_t attr;
1783     pthread_mutexattr_init(&attr);
1784     pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
1785     pthread_mutex_init(&isdo->lock, &attr);
1786     pthread_mutex_lock(&isdo->lock);
1787     pthread_mutexattr_destroy(&attr);
1788 
1789     // copied (and modified) from Java_sun_awt_image_BufImgSurfaceData_initRaster in BufImgSurfaceData.c
1790     {
1791         BufImgSDOps *bisdo =
1792         //(BufImgSDOps*)SurfaceData_InitOps(env, bisd, sizeof(BufImgSDOps));
1793         (BufImgSDOps*)isdo;
1794         //bisdo->sdOps.Lock = BufImg_Lock;
1795         //bisdo->sdOps.GetRasInfo = BufImg_GetRasInfo;
1796         //bisdo->sdOps.Release = BufImg_Release;
1797         //bisdo->sdOps.Unlock = NULL;
1798         //bisdo->sdOps.Dispose = BufImg_Dispose;
1799 
1800         bisdo->array = (*env)->NewWeakGlobalRef(env, array);
1801         if (array != NULL) CHECK_NULL(bisdo->array);
1802         bisdo->offset = offset;
1803         //bisdo->scanStr = scanStr;
1804         bisdo->scanStr = scanStride;
1805         //bisdo->pixStr = pixStr;
1806         bisdo->pixStr = pixelStride;
1807         if (!icm) {
1808             bisdo->lutarray = NULL;
1809             bisdo->lutsize = 0;
1810             bisdo->icm = NULL;
1811         } else {
1812             jobject lutarray = (*env)->GetObjectField(env, icm, rgbID);
1813             bisdo->lutarray = (*env)->NewWeakGlobalRef(env, lutarray);
1814             if (lutarray != NULL) CHECK_NULL(bisdo->lutarray);
1815             bisdo->lutsize = (*env)->GetIntField(env, icm, mapSizeID);
1816             bisdo->icm = (*env)->NewWeakGlobalRef(env, icm);
1817             if (icm != NULL) CHECK_NULL(bisdo->icm);
1818         }
1819         bisdo->rasbounds.x1 = 0;
1820         bisdo->rasbounds.y1 = 0;
1821         bisdo->rasbounds.x2 = width;
1822         bisdo->rasbounds.y2 = height;
1823     }
1824 
1825     isdo->nrOfPixelsOwners = 0;
1826 
1827     isdo->contextInfo                    = sDefaultContextInfo[type];
1828     isdo->imageInfo                        = sDefaultImageInfo[type];
1829 
1830     isdo->contextInfo.bytesPerRow        = width*isdo->contextInfo.bytesPerPixel;
1831     isdo->imageInfo.bytesPerRow            = width*isdo->imageInfo.bytesPerPixel;
1832 
1833     switch (type)
1834     {
1835         case java_awt_image_BufferedImage_TYPE_BYTE_GRAY:
1836             isdo->contextInfo.colorSpace = isdo->imageInfo.colorSpace = gColorspaceGray;
1837             break;
1838         case java_awt_image_BufferedImage_TYPE_USHORT_GRAY:
1839             isdo->contextInfo.colorSpace = gColorspaceRGB;
1840             isdo->imageInfo.colorSpace = gColorspaceGray;
1841             break;
1842         default:
1843             isdo->contextInfo.colorSpace = isdo->imageInfo.colorSpace = gColorspaceRGB;
1844             break;
1845     }
1846     isdo->isSubImage                    = (offset%scanStride != 0) || (scanStride != (pixelStride*width));
1847 
1848     // parameters specifying this image given to us from Java
1849     isdo->javaImageInfo                    = (jint*)((*env)->GetDirectBufferAddress(env, jImageInfo));
1850     isdo->array                            = (array != NULL) ? (*env)->NewGlobalRef(env, array) : NULL;
1851     isdo->offset                        = offset;
1852     isdo->width                            = width;
1853     isdo->height                        = height;
1854     isdo->javaPixelBytes                = pixelStride;
1855     isdo->javaPixelsBytesPerRow            = scanStride;
1856     isdo->icm                            = (icm != NULL) ? (*env)->NewGlobalRef(env, icm) : NULL;
1857     isdo->type                            = type;
1858 
1859     if ((isdo->javaImageInfo[sun_java2d_OSXOffScreenSurfaceData_kImageStolenIndex] == 1) ||
1860         (isdo->type == java_awt_image_BufferedImage_TYPE_CUSTOM))
1861     {
1862         // don't waste (precious, precious) VRAM on stolen or custom images that will be slow no matter what
1863         isdo->contextInfo.useWindowContextReference = NO;
1864     }
1865 
1866     // needed by TYPE_BYTE_INDEXED
1867     isdo->indexedColorTable                = NULL;
1868     isdo->lutData                        = NULL;
1869     isdo->lutDataSize                    = 0;
1870     if ((type == java_awt_image_BufferedImage_TYPE_BYTE_INDEXED) && ((*env)->IsSameObject(env, icm, NULL) == NO))
1871     {
1872         static jclass jc_IndexColorModel = NULL;
1873         if (jc_IndexColorModel == NULL) {
1874             jc_IndexColorModel = (*env)->FindClass(env, "java/awt/image/IndexColorModel");
1875         }
1876         CHECK_NULL(jc_IndexColorModel);
1877         DECLARE_FIELD(jm_rgb, jc_IndexColorModel, "rgb", "[I");
1878         DECLARE_FIELD(jm_transparency, jc_IndexColorModel, "transparency", "I");
1879         DECLARE_FIELD(jm_transparent_index, jc_IndexColorModel, "transparent_index", "I");
1880 
1881         jarray lutarray = (*env)->GetObjectField(env, icm, jm_rgb);
1882         isdo->lutDataSize = (*env)->GetArrayLength(env, lutarray);
1883         if (isdo->lutDataSize > 0)
1884         {
1885             jint transparency = (*env)->GetIntField(env, icm, jm_transparency);
1886             jint transparent_index = -1;
1887             if (transparency == java_awt_Transparency_BITMASK)
1888             {
1889                 transparent_index = (*env)->GetIntField(env, icm, jm_transparent_index);
1890             }
1891 
1892             Pixel32bit* lutdata = (Pixel32bit*)((*env)->GetPrimitiveArrayCritical(env, lutarray, NULL));
1893             if (lutdata != NULL)
1894             {
1895                 isdo->lutData = NULL;
1896 
1897                 isdo->lutData = malloc(isdo->lutDataSize * sizeof(Pixel32bit));
1898                 if (isdo->lutData != NULL)
1899                 {
1900                     if (transparency == java_awt_Transparency_BITMASK)
1901                     {
1902                         Pixel32bit* src = lutdata;
1903                         Pixel32bit* dst = isdo->lutData;
1904                         jint i;
1905                         for (i=0; (unsigned)i<isdo->lutDataSize; i++)
1906                         {
1907                             if (i != transparent_index)
1908                             {
1909                                 *dst = *src;
1910                                 // rdar://problem/3390518 - don't force all indexed colors
1911                                 // to be fully opaque. They could be set up for us.
1912                                 // we used to call:  *dst = 0xff000000 | *src;
1913                                 // but that was forcing colors to be opaque when developers
1914                                 // could have set the alpha.
1915                             }
1916                             else
1917                             {
1918                                 *dst = 0x00000000; // mark as translucent color
1919                             }
1920                             dst++; src++;
1921                         }
1922                     }
1923                     else //if ((transparency == java_awt_Transparency_OPAQUE) || (transparency == java_awt_Transparency_TRANSLUCENT))
1924                     {
1925                         jint mask = 0x00000000;
1926                         // <rdar://4224874> If the color model is OPAQUE than we need to create an opaque image for performance purposes.
1927                         // the default alphaInfo for INDEXED images is kCGImageAlphaFirst. Therefore we need to special case this.
1928                         if ((transparency == java_awt_Transparency_OPAQUE))
1929                         {
1930                             isdo->imageInfo.alphaInfo = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host;
1931                             mask = 0xff000000; // this is just a safeguard to make sure we fill the alpha
1932                         }
1933 
1934                         Pixel32bit* src = lutdata;
1935                         Pixel32bit* dst = isdo->lutData;
1936                         jint i;
1937                         for (i=0; (unsigned)i<isdo->lutDataSize; i++)
1938                         {
1939                             *dst = *src | mask;
1940                             dst++; src++;
1941                         }
1942                     }
1943 
1944                     (*env)->ReleasePrimitiveArrayCritical(env, lutarray, lutdata, 0);
1945                 }
1946                 else
1947                 {
1948                     fprintf(stderr, "ERROR: malloc returns NULL for isdo->lutData in initRaster!\n");
1949                 }
1950             }
1951             else
1952             {
1953                 fprintf(stderr, "ERROR: GetPrimitiveArrayCritical returns NULL for lutdata in initRaster!\n");
1954             }
1955         }
1956         (*env)->DeleteLocalRef(env, lutarray);
1957     }
1958 
1959     QuartzSDOps *qsdo = (QuartzSDOps*)isdo;
1960     qsdo->BeginSurface                    = ImageSD_startCGContext;
1961     qsdo->FinishSurface                    = ImageSD_finishCGContext;
1962 
1963     qsdo->javaGraphicsStates            = (jint*)((*env)->GetDirectBufferAddress(env, jGraphicsState));
1964     qsdo->javaGraphicsStatesObjects        = (*env)->NewGlobalRef(env, jGraphicsStateObject);
1965 
1966     qsdo->graphicsStateInfo.batchedLines = NULL;
1967     qsdo->graphicsStateInfo.batchedLinesCount = 0;
1968 
1969     SurfaceDataOps *sdo = (SurfaceDataOps*)qsdo;
1970     sdo->Lock        = ImageSD_Lock;
1971     sdo->Unlock        = ImageSD_Unlock;
1972     sdo->GetRasInfo    = ImageSD_GetRasInfo;
1973     sdo->Release    = ImageSD_Release;
1974     sdo->Setup        = NULL;
1975     sdo->Dispose    = ImageSD_dispose;
1976 
1977     pthread_mutex_unlock(&isdo->lock);
1978 
1979 //PrintImageInfo(isdo);
1980 }
1981 
1982 JNIEXPORT void JNICALL Java_sun_java2d_OSXOffScreenSurfaceData_initCustomRaster(JNIEnv* env, jobject bisd, jobject array, jint width, jint height,
1983                                                                                     jobject jGraphicsState, jobject jGraphicsStateObject, jobject jImageInfo)
1984 {
1985 PRINT("Java_sun_java2d_OSXOffScreenSurfaceData_initCustomRaster")
1986     jint offset = 0;
1987     jint pixelStride = 4;
1988     jint scanStride = pixelStride*width;
1989     jobject icm = NULL;
1990     jint type = java_awt_image_BufferedImage_TYPE_CUSTOM;
1991 
1992     Java_sun_java2d_OSXOffScreenSurfaceData_initRaster(env, bisd, array, offset, width, height, pixelStride, scanStride, icm, type, jGraphicsState, jGraphicsStateObject, jImageInfo);
1993 }
1994 
1995 JNIEXPORT void JNICALL Java_sun_java2d_OSXOffScreenSurfaceData_syncToJavaPixels(JNIEnv *env, jobject bisd)
1996 {
1997 PRINT("Java_sun_java2d_OSXOffScreenSurfaceData_syncToJavaPixels")
1998 
1999     syncToJavaPixels(env, (ImageSDOps*)SurfaceData_GetOps(env, bisd));
2000 }
2001 
2002 JNIEXPORT jboolean JNICALL Java_sun_java2d_OSXOffScreenSurfaceData_xorSurfacePixels
2003   (JNIEnv *env, jobject dstIsd, jobject srcIsd, jint colorXOR, jint x, jint y, jint w, jint h)
2004 {
2005 PRINT("Java_sun_java2d_OSXOffScreenSurfaceData_xorSurfacePixels")
2006     return xorSurfacePixels(env, dstIsd, srcIsd, colorXOR, x, y, w, h);
2007 }
2008 
2009 JNIEXPORT jboolean JNICALL Java_sun_java2d_OSXOffScreenSurfaceData_clearSurfacePixels
2010   (JNIEnv *env, jobject bisd, jint w, jint h)
2011 {
2012 PRINT("Java_sun_java2d_OSXOffScreenSurfaceData_clearSurfacePixels")
2013     return clearSurfacePixels(env, bisd, w, h);
2014 
2015 }