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