1 /* 2 * Copyright (c) 1999, 2018, 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 #include "BufImgSurfaceData.h" 27 #include <stdlib.h> 28 29 #include "sun_awt_image_BufImgSurfaceData.h" 30 31 #include "img_util_md.h" 32 #include "jni_util.h" 33 /* Define uintptr_t */ 34 #include "gdefs.h" 35 #include "Disposer.h" 36 37 /** 38 * This include file contains support code for loops using the 39 * SurfaceData interface to talk to an X11 drawable from native 40 * code. 41 */ 42 43 static LockFunc BufImg_Lock; 44 static GetRasInfoFunc BufImg_GetRasInfo; 45 static ReleaseFunc BufImg_Release; 46 static DisposeFunc BufImg_Dispose; 47 48 static ColorData *BufImg_SetupICM(JNIEnv *env, BufImgSDOps *bisdo); 49 50 static jfieldID rgbID; 51 static jfieldID mapSizeID; 52 static jfieldID colorDataID; 53 static jfieldID pDataID; 54 static jfieldID allGrayID; 55 56 static jclass clsICMCD; 57 static jmethodID initICMCDmID; 58 /* 59 * Class: sun_awt_image_BufImgSurfaceData 60 * Method: initIDs 61 * Signature: ()V 62 */ 63 JNIEXPORT void JNICALL 64 Java_sun_awt_image_BufImgSurfaceData_initIDs 65 (JNIEnv *env, jclass bisd, jclass icm, jclass cd) 66 { 67 if (sizeof(BufImgRIPrivate) > SD_RASINFO_PRIVATE_SIZE) { 68 JNU_ThrowInternalError(env, "Private RasInfo structure too large!"); 69 return; 70 } 71 72 clsICMCD = (*env)->NewWeakGlobalRef(env, cd); 73 JNU_CHECK_EXCEPTION(env); 74 CHECK_NULL(initICMCDmID = (*env)->GetMethodID(env, cd, "<init>", "(J)V")); 75 CHECK_NULL(pDataID = (*env)->GetFieldID(env, cd, "pData", "J")); 76 CHECK_NULL(rgbID = (*env)->GetFieldID(env, icm, "rgb", "[I")); 77 CHECK_NULL(allGrayID = (*env)->GetFieldID(env, icm, "allgrayopaque", "Z")); 78 CHECK_NULL(mapSizeID = (*env)->GetFieldID(env, icm, "map_size", "I")); 79 CHECK_NULL(colorDataID = (*env)->GetFieldID(env, icm, "colorData", 80 "Lsun/awt/image/BufImgSurfaceData$ICMColorData;")); 81 } 82 83 /* 84 * Class: sun_awt_image_BufImgSurfaceData 85 * Method: initOps 86 * Signature: (Ljava/lang/Object;IIIII)V 87 */ 88 JNIEXPORT void JNICALL 89 Java_sun_awt_image_BufImgSurfaceData_initRaster(JNIEnv *env, jobject bisd, 90 jobject array, 91 jint offset, jint bitoffset, 92 jint width, jint height, 93 jint pixStr, jint scanStr, 94 jobject icm) 95 { 96 BufImgSDOps *bisdo = 97 (BufImgSDOps*)SurfaceData_InitOps(env, bisd, sizeof(BufImgSDOps)); 98 if (bisdo == NULL) { 99 JNU_ThrowOutOfMemoryError(env, "Initialization of SurfaceData failed."); 100 return; 101 } 102 bisdo->sdOps.Lock = BufImg_Lock; 103 bisdo->sdOps.GetRasInfo = BufImg_GetRasInfo; 104 bisdo->sdOps.Release = BufImg_Release; 105 bisdo->sdOps.Unlock = NULL; 106 bisdo->sdOps.Dispose = BufImg_Dispose; 107 bisdo->array = (*env)->NewWeakGlobalRef(env, array); 108 JNU_CHECK_EXCEPTION(env); 109 bisdo->offset = offset; 110 bisdo->bitoffset = bitoffset; 111 bisdo->scanStr = scanStr; 112 bisdo->pixStr = pixStr; 113 if (JNU_IsNull(env, icm)) { 114 bisdo->lutarray = NULL; 115 bisdo->lutsize = 0; 116 bisdo->icm = NULL; 117 } else { 118 jobject lutarray = (*env)->GetObjectField(env, icm, rgbID); 119 bisdo->lutarray = (*env)->NewWeakGlobalRef(env, lutarray); 120 JNU_CHECK_EXCEPTION(env); 121 bisdo->lutsize = (*env)->GetIntField(env, icm, mapSizeID); 122 bisdo->icm = (*env)->NewWeakGlobalRef(env, icm); 123 } 124 bisdo->rasbounds.x1 = 0; 125 bisdo->rasbounds.y1 = 0; 126 bisdo->rasbounds.x2 = width; 127 bisdo->rasbounds.y2 = height; 128 } 129 130 /* 131 * Releases native structures associated with BufImgSurfaceData.ICMColorData. 132 */ 133 static void BufImg_Dispose_ICMColorData(JNIEnv *env, jlong pData) 134 { 135 ColorData *cdata = (ColorData*)jlong_to_ptr(pData); 136 freeICMColorData(cdata); 137 } 138 139 /* 140 * Method for disposing native BufImgSD 141 */ 142 static void BufImg_Dispose(JNIEnv *env, SurfaceDataOps *ops) 143 { 144 /* ops is assumed non-null as it is checked in SurfaceData_DisposeOps */ 145 BufImgSDOps *bisdo = (BufImgSDOps *)ops; 146 (*env)->DeleteWeakGlobalRef(env, bisdo->array); 147 if (bisdo->lutarray != NULL) { 148 (*env)->DeleteWeakGlobalRef(env, bisdo->lutarray); 149 } 150 if (bisdo->icm != NULL) { 151 (*env)->DeleteWeakGlobalRef(env, bisdo->icm); 152 } 153 } 154 155 static jint BufImg_Lock(JNIEnv *env, 156 SurfaceDataOps *ops, 157 SurfaceDataRasInfo *pRasInfo, 158 jint lockflags) 159 { 160 BufImgSDOps *bisdo = (BufImgSDOps *)ops; 161 BufImgRIPrivate *bipriv = (BufImgRIPrivate *) &(pRasInfo->priv); 162 163 if ((lockflags & (SD_LOCK_LUT)) != 0 && JNU_IsNull(env, bisdo->lutarray)) { 164 /* REMIND: Should this be an InvalidPipe exception? */ 165 JNU_ThrowNullPointerException(env, "Attempt to lock missing colormap"); 166 return SD_FAILURE; 167 } 168 if ((lockflags & SD_LOCK_INVCOLOR) != 0 || 169 (lockflags & SD_LOCK_INVGRAY) != 0) 170 { 171 bipriv->cData = BufImg_SetupICM(env, bisdo); 172 if (bipriv->cData == NULL) { 173 (*env)->ExceptionClear(env); 174 JNU_ThrowNullPointerException(env, "Could not initialize inverse tables"); 175 return SD_FAILURE; 176 } 177 } else { 178 bipriv->cData = NULL; 179 } 180 181 bipriv->lockFlags = lockflags; 182 bipriv->base = NULL; 183 bipriv->lutbase = NULL; 184 185 SurfaceData_IntersectBounds(&pRasInfo->bounds, &bisdo->rasbounds); 186 187 return SD_SUCCESS; 188 } 189 190 static void BufImg_GetRasInfo(JNIEnv *env, 191 SurfaceDataOps *ops, 192 SurfaceDataRasInfo *pRasInfo) 193 { 194 BufImgSDOps *bisdo = (BufImgSDOps *)ops; 195 BufImgRIPrivate *bipriv = (BufImgRIPrivate *) &(pRasInfo->priv); 196 197 if ((bipriv->lockFlags & (SD_LOCK_RD_WR)) != 0) { 198 bipriv->base = 199 (*env)->GetPrimitiveArrayCritical(env, bisdo->array, NULL); 200 CHECK_NULL(bipriv->base); 201 } 202 if ((bipriv->lockFlags & (SD_LOCK_LUT)) != 0) { 203 bipriv->lutbase = 204 (*env)->GetPrimitiveArrayCritical(env, bisdo->lutarray, NULL); 205 } 206 207 if (bipriv->base == NULL) { 208 pRasInfo->rasBase = NULL; 209 pRasInfo->pixelStride = 0; 210 pRasInfo->pixelBitOffset = 0; 211 pRasInfo->scanStride = 0; 212 } else { 213 pRasInfo->rasBase = (void *) 214 (((uintptr_t) bipriv->base) + bisdo->offset); 215 pRasInfo->pixelStride = bisdo->pixStr; 216 pRasInfo->pixelBitOffset = bisdo->bitoffset; 217 pRasInfo->scanStride = bisdo->scanStr; 218 } 219 if (bipriv->lutbase == NULL) { 220 pRasInfo->lutBase = NULL; 221 pRasInfo->lutSize = 0; 222 } else { 223 pRasInfo->lutBase = bipriv->lutbase; 224 pRasInfo->lutSize = bisdo->lutsize; 225 } 226 if (bipriv->cData == NULL) { 227 pRasInfo->invColorTable = NULL; 228 pRasInfo->redErrTable = NULL; 229 pRasInfo->grnErrTable = NULL; 230 pRasInfo->bluErrTable = NULL; 231 pRasInfo->representsPrimaries = 0; 232 } else { 233 pRasInfo->invColorTable = bipriv->cData->img_clr_tbl; 234 pRasInfo->redErrTable = bipriv->cData->img_oda_red; 235 pRasInfo->grnErrTable = bipriv->cData->img_oda_green; 236 pRasInfo->bluErrTable = bipriv->cData->img_oda_blue; 237 pRasInfo->invGrayTable = bipriv->cData->pGrayInverseLutData; 238 pRasInfo->representsPrimaries = bipriv->cData->representsPrimaries; 239 } 240 } 241 242 static void BufImg_Release(JNIEnv *env, 243 SurfaceDataOps *ops, 244 SurfaceDataRasInfo *pRasInfo) 245 { 246 BufImgSDOps *bisdo = (BufImgSDOps *)ops; 247 BufImgRIPrivate *bipriv = (BufImgRIPrivate *) &(pRasInfo->priv); 248 249 if (bipriv->base != NULL) { 250 jint mode = (((bipriv->lockFlags & (SD_LOCK_WRITE)) != 0) 251 ? 0 : JNI_ABORT); 252 (*env)->ReleasePrimitiveArrayCritical(env, bisdo->array, 253 bipriv->base, mode); 254 } 255 if (bipriv->lutbase != NULL) { 256 (*env)->ReleasePrimitiveArrayCritical(env, bisdo->lutarray, 257 bipriv->lutbase, JNI_ABORT); 258 } 259 } 260 261 static int calculatePrimaryColorsApproximation(int* cmap, unsigned char* cube, int cube_size) { 262 int i, j, k; 263 int index, value, color; 264 // values calculated from cmap 265 int r, g, b; 266 // maximum positive/negative variation allowed for r, g, b values for primary colors 267 int delta = 5; 268 // get the primary color cmap indices from corner of inverse color table 269 for (i = 0; i < cube_size; i += (cube_size - 1)) { 270 for (j = 0; j < cube_size; j += (cube_size - 1)) { 271 for (k = 0; k < cube_size; k += (cube_size - 1)) { 272 // calculate inverse color table index 273 index = i + cube_size * (j + cube_size * k); 274 // get value present in corners of inverse color table 275 value = cube[index]; 276 // use the corner values as index for cmap 277 color = cmap[value]; 278 // extract r,g,b values from cmap value 279 r = ((color) >> 16) & 0xff; 280 g = ((color) >> 8) & 0xff; 281 b = color & 0xff; 282 /* 283 * If i/j/k value is 0 optimum value of b/g/r should be 0 but we allow 284 * maximum positive variation of 5. If i/j/k value is 31 optimum value 285 * of b/g/r should be 255 but we allow maximum negative variation of 5. 286 */ 287 if (i == 0) { 288 if (b > delta) 289 return 0; 290 } else { 291 if (b < (255 - delta)) 292 return 0; 293 } 294 if (j == 0) { 295 if (g > delta) 296 return 0; 297 } else { 298 if (g < (255 - delta)) 299 return 0; 300 } 301 if (k == 0) { 302 if (r > delta) 303 return 0; 304 } else { 305 if (r < (255 - delta)) 306 return 0; 307 } 308 } 309 } 310 } 311 return 1; 312 } 313 314 static ColorData *BufImg_SetupICM(JNIEnv *env, 315 BufImgSDOps *bisdo) 316 { 317 ColorData *cData = NULL; 318 jobject colorData; 319 320 if (JNU_IsNull(env, bisdo->icm)) { 321 return (ColorData *) NULL; 322 } 323 324 colorData = (*env)->GetObjectField(env, bisdo->icm, colorDataID); 325 326 if (JNU_IsNull(env, colorData)) { 327 if (JNU_IsNull(env, clsICMCD)) { 328 // we are unable to create a wrapper object 329 return (ColorData*)NULL; 330 } 331 } else { 332 cData = (ColorData*)JNU_GetLongFieldAsPtr(env, colorData, pDataID); 333 } 334 335 if (cData != NULL) { 336 return cData; 337 } 338 339 cData = (ColorData*)calloc(1, sizeof(ColorData)); 340 341 if (cData != NULL) { 342 jboolean allGray 343 = (*env)->GetBooleanField(env, bisdo->icm, allGrayID); 344 int *pRgb = (int *) 345 ((*env)->GetPrimitiveArrayCritical(env, bisdo->lutarray, NULL)); 346 347 if (pRgb == NULL) { 348 free(cData); 349 return (ColorData*)NULL; 350 } 351 352 cData->img_clr_tbl = initCubemap(pRgb, bisdo->lutsize, 32); 353 if (cData->img_clr_tbl == NULL) { 354 free(cData); 355 return (ColorData*)NULL; 356 } 357 cData->representsPrimaries = calculatePrimaryColorsApproximation(pRgb, cData->img_clr_tbl, 32); 358 if (allGray == JNI_TRUE) { 359 initInverseGrayLut(pRgb, bisdo->lutsize, cData); 360 } 361 (*env)->ReleasePrimitiveArrayCritical(env, bisdo->lutarray, pRgb, 362 JNI_ABORT); 363 364 initDitherTables(cData); 365 366 if (JNU_IsNull(env, colorData)) { 367 jlong pData = ptr_to_jlong(cData); 368 colorData = (*env)->NewObjectA(env, clsICMCD, initICMCDmID, (jvalue *)&pData); 369 370 if ((*env)->ExceptionCheck(env)) 371 { 372 free(cData); 373 return (ColorData*)NULL; 374 } 375 376 (*env)->SetObjectField(env, bisdo->icm, colorDataID, colorData); 377 Disposer_AddRecord(env, colorData, BufImg_Dispose_ICMColorData, pData); 378 } 379 } 380 381 return cData; 382 }