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 | } |
383 | |