1/*
2 * Copyright (c) 1999, 2013, 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
39static jclass pInvalidPipeClass;
40static jclass pNullSurfaceDataClass;
41static jfieldID pDataID;
42static jfieldID allGrayID;
43
44jfieldID validID;
45GeneralDisposeFunc SurfaceData_DisposeOps;
46
47#define InitClass(var, env, name) \
48do { \
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) \
56do { \
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) \
64do { \
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 */
78JNIEXPORT void JNICALL
79Java_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 */
101JNIEXPORT jboolean JNICALL
102Java_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
111static SurfaceDataOps *
112GetSDOps(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
136JNIEXPORT SurfaceDataOps * JNICALL
137SurfaceData_GetOps(JNIEnv *env, jobject sData)
138{
139    return GetSDOps(env, sData, JNI_TRUE);
140}
141
142JNIEXPORT SurfaceDataOps * JNICALL
143SurfaceData_GetOpsNoSetup(JNIEnv *env, jobject sData)
144{
145    return GetSDOps(env, sData, JNI_FALSE);
146}
147
148JNIEXPORT void JNICALL
149SurfaceData_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
162JNIEXPORT void JNICALL
163SurfaceData_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
171JNIEXPORT void JNICALL
172SurfaceData_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
181JNIEXPORT void JNICALL
182SurfaceData_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
192JNIEXPORT void JNICALL
193SurfaceData_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
218JNIEXPORT void JNICALL
219SurfaceData_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
234SurfaceDataOps *SurfaceData_InitOps(JNIEnv *env, jobject sData, int opsSize)
235{
236    SurfaceDataOps *ops = malloc(opsSize);
237    SurfaceData_SetOps(env, sData, ops);
238    if (ops != NULL) {
239        memset(ops, 0, opsSize);
240        if (!(*env)->ExceptionCheck(env)) {
241            ops->sdObject = (*env)->NewWeakGlobalRef(env, sData);
242        }
243    }
244    return ops;
245}
246
247void SurfaceData_DisposeOps(JNIEnv *env, jlong ops)
248{
249    if (ops != 0) {
250        SurfaceDataOps *sdops = (SurfaceDataOps*)jlong_to_ptr(ops);
251        /* Invoke the ops-specific disposal function */
252        SurfaceData_InvokeDispose(env, sdops);
253        (*env)->DeleteWeakGlobalRef(env, sdops->sdObject);
254        free(sdops);
255    }
256}
257