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
  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
 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 *
 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
 137 SurfaceData_GetOps(JNIEnv *env, jobject sData)
 138 {
 139     return GetSDOps(env, sData, JNI_TRUE);
 140 }
 141 
 142 JNIEXPORT SurfaceDataOps * JNICALL
 143 SurfaceData_GetOpsNoSetup(JNIEnv *env, jobject sData)
 144 {
 145     return GetSDOps(env, sData, JNI_FALSE);
 146 }
 147 
 148 JNIEXPORT void JNICALL
 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
 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
 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
 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
 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
 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
 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 
 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 }