1 /*
2  * Copyright (c) 1999, 2019, 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
Java_sun_awt_image_BufImgSurfaceData_initIDs(JNIEnv * env,jclass bisd,jclass icm,jclass cd)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
Java_sun_awt_image_BufImgSurfaceData_initRaster(JNIEnv * env,jobject bisd,jobject array,jint offset,jint bitoffset,jint width,jint height,jint pixStr,jint scanStr,jobject icm)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  */
BufImg_Dispose_ICMColorData(JNIEnv * env,jlong pData)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  */
BufImg_Dispose(JNIEnv * env,SurfaceDataOps * ops)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 
BufImg_Lock(JNIEnv * env,SurfaceDataOps * ops,SurfaceDataRasInfo * pRasInfo,jint lockflags)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 
BufImg_GetRasInfo(JNIEnv * env,SurfaceDataOps * ops,SurfaceDataRasInfo * pRasInfo)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     } else {
232         pRasInfo->invColorTable = bipriv->cData->img_clr_tbl;
233         pRasInfo->redErrTable = bipriv->cData->img_oda_red;
234         pRasInfo->grnErrTable = bipriv->cData->img_oda_green;
235         pRasInfo->bluErrTable = bipriv->cData->img_oda_blue;
236         pRasInfo->invGrayTable = bipriv->cData->pGrayInverseLutData;
237     }
238 }
239 
BufImg_Release(JNIEnv * env,SurfaceDataOps * ops,SurfaceDataRasInfo * pRasInfo)240 static void BufImg_Release(JNIEnv *env,
241                            SurfaceDataOps *ops,
242                            SurfaceDataRasInfo *pRasInfo)
243 {
244     BufImgSDOps *bisdo = (BufImgSDOps *)ops;
245     BufImgRIPrivate *bipriv = (BufImgRIPrivate *) &(pRasInfo->priv);
246 
247     if (bipriv->base != NULL) {
248         jint mode = (((bipriv->lockFlags & (SD_LOCK_WRITE)) != 0)
249                      ? 0 : JNI_ABORT);
250         (*env)->ReleasePrimitiveArrayCritical(env, bisdo->array,
251                                               bipriv->base, mode);
252     }
253     if (bipriv->lutbase != NULL) {
254         (*env)->ReleasePrimitiveArrayCritical(env, bisdo->lutarray,
255                                               bipriv->lutbase, JNI_ABORT);
256     }
257 }
258 
BufImg_SetupICM(JNIEnv * env,BufImgSDOps * bisdo)259 static ColorData *BufImg_SetupICM(JNIEnv *env,
260                                   BufImgSDOps *bisdo)
261 {
262     ColorData *cData = NULL;
263     jobject colorData;
264 
265     if (JNU_IsNull(env, bisdo->icm)) {
266         return (ColorData *) NULL;
267     }
268 
269     colorData = (*env)->GetObjectField(env, bisdo->icm, colorDataID);
270 
271     if (JNU_IsNull(env, colorData)) {
272         if (JNU_IsNull(env, clsICMCD)) {
273             // we are unable to create a wrapper object
274             return (ColorData*)NULL;
275         }
276     } else {
277         cData = (ColorData*)JNU_GetLongFieldAsPtr(env, colorData, pDataID);
278     }
279 
280     if (cData != NULL) {
281         return cData;
282     }
283 
284     cData = (ColorData*)calloc(1, sizeof(ColorData));
285 
286     if (cData != NULL) {
287         jboolean allGray
288             = (*env)->GetBooleanField(env, bisdo->icm, allGrayID);
289         int *pRgb = (int *)
290             ((*env)->GetPrimitiveArrayCritical(env, bisdo->lutarray, NULL));
291 
292         if (pRgb == NULL) {
293             free(cData);
294             return (ColorData*)NULL;
295         }
296 
297         cData->img_clr_tbl = initCubemap(pRgb, bisdo->lutsize, 32);
298         if (cData->img_clr_tbl == NULL) {
299             (*env)->ReleasePrimitiveArrayCritical(env, bisdo->lutarray, pRgb, JNI_ABORT);
300             free(cData);
301             return (ColorData*)NULL;
302         }
303         if (allGray == JNI_TRUE) {
304             initInverseGrayLut(pRgb, bisdo->lutsize, cData);
305         }
306         (*env)->ReleasePrimitiveArrayCritical(env, bisdo->lutarray, pRgb,
307                                               JNI_ABORT);
308 
309         initDitherTables(cData);
310 
311         if (JNU_IsNull(env, colorData)) {
312             jlong pData = ptr_to_jlong(cData);
313             colorData = (*env)->NewObjectA(env, clsICMCD, initICMCDmID, (jvalue *)&pData);
314 
315             if ((*env)->ExceptionCheck(env))
316             {
317                 free(cData);
318                 return (ColorData*)NULL;
319             }
320 
321             (*env)->SetObjectField(env, bisdo->icm, colorDataID, colorData);
322             Disposer_AddRecord(env, colorData, BufImg_Dispose_ICMColorData, pData);
323         }
324     }
325 
326     return cData;
327 }
328