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