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 "SurfaceData.h"
27 
28 #include "jni_util.h"
29 #include "Disposer.h"
30 
31 #include "stdlib.h"
32 #include "string.h"
33 
34 /**
35  * This include file contains information on how to use a SurfaceData
36  * object from native code.
37  */
38 
39 static jclass pInvalidPipeClass;
40 static jclass pNullSurfaceDataClass;
41 static jfieldID pDataID;
42 static jfieldID allGrayID;
43 
44 jfieldID validID;
45 GeneralDisposeFunc SurfaceData_DisposeOps;
46 
47 #define InitClass(var, env, name) \
48 do { \
49     var = (*env)->FindClass(env, name); \
50     if (var == NULL) { \
51         return; \
52     } \
53 } while (0)
54 
55 #define InitField(var, env, jcl, name, type) \
56 do { \
57     var = (*env)->GetFieldID(env, jcl, name, type); \
58     if (var == NULL) { \
59         return; \
60     } \
61 } while (0)
62 
63 #define InitGlobalClassRef(var, env, name) \
64 do { \
65     jobject jtmp; \
66     InitClass(jtmp, env, name); \
67     var = (*env)->NewGlobalRef(env, jtmp); \
68     if (var == NULL) { \
69         return; \
70     } \
71 } while (0)
72 
73 /*
74  * Class:     sun_java2d_SurfaceData
75  * Method:    initIDs
76  * Signature: ()V
77  */
78 JNIEXPORT void JNICALL
Java_sun_java2d_SurfaceData_initIDs(JNIEnv * env,jclass sd)79 Java_sun_java2d_SurfaceData_initIDs(JNIEnv *env, jclass sd)
80 {
81     jclass pICMClass;
82 
83     InitGlobalClassRef(pInvalidPipeClass, env,
84                        "sun/java2d/InvalidPipeException");
85 
86     InitGlobalClassRef(pNullSurfaceDataClass, env,
87                        "sun/java2d/NullSurfaceData");
88 
89     InitField(pDataID, env, sd, "pData", "J");
90     InitField(validID, env, sd, "valid", "Z");
91 
92     InitClass(pICMClass, env, "java/awt/image/IndexColorModel");
93     InitField(allGrayID, env, pICMClass, "allgrayopaque", "Z");
94 }
95 
96 /*
97  * Class:     sun_java2d_SurfaceData
98  * Method:    isOpaqueGray
99  * Signature: ()Z
100  */
101 JNIEXPORT jboolean JNICALL
Java_sun_java2d_SurfaceData_isOpaqueGray(JNIEnv * env,jclass sdClass,jobject icm)102 Java_sun_java2d_SurfaceData_isOpaqueGray(JNIEnv *env, jclass sdClass,
103                                          jobject icm)
104 {
105     if (icm == NULL) {
106         return JNI_FALSE;
107     }
108     return (*env)->GetBooleanField(env, icm, allGrayID);
109 }
110 
111 static SurfaceDataOps *
GetSDOps(JNIEnv * env,jobject sData,jboolean callSetup)112 GetSDOps(JNIEnv *env, jobject sData, jboolean callSetup)
113 {
114     SurfaceDataOps *ops;
115     if (JNU_IsNull(env, sData)) {
116         JNU_ThrowNullPointerException(env, "surfaceData");
117         return NULL;
118     }
119     ops = (SurfaceDataOps *)JNU_GetLongFieldAsPtr(env, sData, pDataID);
120     if (ops == NULL) {
121         if (!(*env)->ExceptionOccurred(env) &&
122             !(*env)->IsInstanceOf(env, sData, pNullSurfaceDataClass))
123         {
124             if (!(*env)->GetBooleanField(env, sData, validID)) {
125                 SurfaceData_ThrowInvalidPipeException(env, "invalid data");
126             } else {
127                 JNU_ThrowNullPointerException(env, "native ops missing");
128             }
129         }
130     } else if (callSetup) {
131         SurfaceData_InvokeSetup(env, ops);
132     }
133     return ops;
134 }
135 
136 JNIEXPORT SurfaceDataOps * JNICALL
SurfaceData_GetOps(JNIEnv * env,jobject sData)137 SurfaceData_GetOps(JNIEnv *env, jobject sData)
138 {
139     return GetSDOps(env, sData, JNI_TRUE);
140 }
141 
142 JNIEXPORT SurfaceDataOps * JNICALL
SurfaceData_GetOpsNoSetup(JNIEnv * env,jobject sData)143 SurfaceData_GetOpsNoSetup(JNIEnv *env, jobject sData)
144 {
145     return GetSDOps(env, sData, JNI_FALSE);
146 }
147 
148 JNIEXPORT void JNICALL
SurfaceData_SetOps(JNIEnv * env,jobject sData,SurfaceDataOps * ops)149 SurfaceData_SetOps(JNIEnv *env, jobject sData, SurfaceDataOps *ops)
150 {
151     if (JNU_GetLongFieldAsPtr(env, sData, pDataID) == NULL) {
152         JNU_SetLongFieldFromPtr(env, sData, pDataID, ops);
153         /* Register the data for disposal */
154         Disposer_AddRecord(env, sData,
155                            SurfaceData_DisposeOps,
156                            ptr_to_jlong(ops));
157     } else {
158         JNU_ThrowInternalError(env, "Attempting to set SurfaceData ops twice");
159     }
160 }
161 
162 JNIEXPORT void JNICALL
SurfaceData_ThrowInvalidPipeException(JNIEnv * env,const char * msg)163 SurfaceData_ThrowInvalidPipeException(JNIEnv *env, const char *msg)
164 {
165     (*env)->ThrowNew(env, pInvalidPipeClass, msg);
166 }
167 
168 #define GETMIN(v1, v2)          (((v1) > (t=(v2))) && ((v1) = t))
169 #define GETMAX(v1, v2)          (((v1) < (t=(v2))) && ((v1) = t))
170 
171 JNIEXPORT void JNICALL
SurfaceData_IntersectBounds(SurfaceDataBounds * dst,SurfaceDataBounds * src)172 SurfaceData_IntersectBounds(SurfaceDataBounds *dst, SurfaceDataBounds *src)
173 {
174     int t;
175     GETMAX(dst->x1, src->x1);
176     GETMAX(dst->y1, src->y1);
177     GETMIN(dst->x2, src->x2);
178     GETMIN(dst->y2, src->y2);
179 }
180 
181 JNIEXPORT void JNICALL
SurfaceData_IntersectBoundsXYXY(SurfaceDataBounds * bounds,jint x1,jint y1,jint x2,jint y2)182 SurfaceData_IntersectBoundsXYXY(SurfaceDataBounds *bounds,
183                                 jint x1, jint y1, jint x2, jint y2)
184 {
185     int t;
186     GETMAX(bounds->x1, x1);
187     GETMAX(bounds->y1, y1);
188     GETMIN(bounds->x2, x2);
189     GETMIN(bounds->y2, y2);
190 }
191 
192 JNIEXPORT void JNICALL
SurfaceData_IntersectBoundsXYWH(SurfaceDataBounds * bounds,jint x,jint y,jint w,jint h)193 SurfaceData_IntersectBoundsXYWH(SurfaceDataBounds *bounds,
194                                 jint x, jint y, jint w, jint h)
195 {
196     w = (w <= 0) ? x : x+w;
197     if (w < x) {
198         w = 0x7fffffff;
199     }
200     if (bounds->x1 < x) {
201         bounds->x1 = x;
202     }
203     if (bounds->x2 > w) {
204         bounds->x2 = w;
205     }
206     h = (h <= 0) ? y : y+h;
207     if (h < y) {
208         h = 0x7fffffff;
209     }
210     if (bounds->y1 < y) {
211         bounds->y1 = y;
212     }
213     if (bounds->y2 > h) {
214         bounds->y2 = h;
215     }
216 }
217 
218 JNIEXPORT void JNICALL
SurfaceData_IntersectBlitBounds(SurfaceDataBounds * src,SurfaceDataBounds * dst,jint dx,jint dy)219 SurfaceData_IntersectBlitBounds(SurfaceDataBounds *src,
220                                 SurfaceDataBounds *dst,
221                                 jint dx, jint dy)
222 {
223     int t;
224     GETMAX(dst->x1, src->x1 + dx);
225     GETMAX(dst->y1, src->y1 + dy);
226     GETMIN(dst->x2, src->x2 + dx);
227     GETMIN(dst->y2, src->y2 + dy);
228     GETMAX(src->x1, dst->x1 - dx);
229     GETMAX(src->y1, dst->y1 - dy);
230     GETMIN(src->x2, dst->x2 - dx);
231     GETMIN(src->y2, dst->y2 - dy);
232 }
233 
234 JNIEXPORT SurfaceDataOps * JNICALL
SurfaceData_InitOps(JNIEnv * env,jobject sData,int opsSize)235 SurfaceData_InitOps(JNIEnv *env, jobject sData, int opsSize)
236 {
237     SurfaceDataOps *ops = malloc(opsSize);
238     SurfaceData_SetOps(env, sData, ops);
239     if (ops != NULL) {
240         memset(ops, 0, opsSize);
241         if (!(*env)->ExceptionCheck(env)) {
242             ops->sdObject = (*env)->NewWeakGlobalRef(env, sData);
243         }
244     }
245     return ops;
246 }
247 
SurfaceData_DisposeOps(JNIEnv * env,jlong ops)248 void SurfaceData_DisposeOps(JNIEnv *env, jlong ops)
249 {
250     if (ops != 0) {
251         SurfaceDataOps *sdops = (SurfaceDataOps*)jlong_to_ptr(ops);
252         /* Invoke the ops-specific disposal function */
253         SurfaceData_InvokeDispose(env, sdops);
254         (*env)->DeleteWeakGlobalRef(env, sdops->sdObject);
255         free(sdops);
256     }
257 }
258