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
43static LockFunc BufImg_Lock;
44static GetRasInfoFunc BufImg_GetRasInfo;
45static ReleaseFunc BufImg_Release;
46static DisposeFunc BufImg_Dispose;
47
48static ColorData *BufImg_SetupICM(JNIEnv *env, BufImgSDOps *bisdo);
49
50static jfieldID rgbID;
51static jfieldID mapSizeID;
52static jfieldID colorDataID;
53static jfieldID pDataID;
54static jfieldID allGrayID;
55
56static jclass clsICMCD;
57static jmethodID initICMCDmID;
58/*
59 * Class: sun_awt_image_BufImgSurfaceData
60 * Method: initIDs
61 * Signature: ()V
62 */
63JNIEXPORT void JNICALL
64Java_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 */
88JNIEXPORT void JNICALL
89Java_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 */
133static 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 */
142static 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
155static 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
190static 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
242static 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
261static 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
314static 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