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