1/* 2 * Copyright (c) 2002, 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 <stdlib.h> 27 28#include "jni_util.h" 29 30#include "Region.h" 31#include "sizecalc.h" 32 33static jfieldID endIndexID; 34static jfieldID bandsID; 35static jfieldID loxID; 36static jfieldID loyID; 37static jfieldID hixID; 38static jfieldID hiyID; 39 40#define InitField(var, env, jcl, name, type) \ 41do { \ 42 var = (*env)->GetFieldID(env, jcl, name, type); \ 43 if (var == NULL) { \ 44 return; \ 45 } \ 46} while (0) 47 48/* 49 * Class: sun_java2d_pipe_Region 50 * Method: initIDs 51 * Signature: ()V 52 */ 53JNIEXPORT void JNICALL 54Java_sun_java2d_pipe_Region_initIDs(JNIEnv *env, jclass reg) 55{ 56 InitField(endIndexID, env, reg, "endIndex", "I"); 57 InitField(bandsID, env, reg, "bands", "[I"); 58 59 InitField(loxID, env, reg, "lox", "I"); 60 InitField(loyID, env, reg, "loy", "I"); 61 InitField(hixID, env, reg, "hix", "I"); 62 InitField(hiyID, env, reg, "hiy", "I"); 63} 64 65JNIEXPORT jint JNICALL 66Region_GetInfo(JNIEnv *env, jobject region, RegionData *pRgnInfo) 67{ 68 if (JNU_IsNull(env, region)) { 69 pRgnInfo->bounds.x1 = pRgnInfo->bounds.y1 = 0x80000000; 70 pRgnInfo->bounds.x2 = pRgnInfo->bounds.y2 = 0x7fffffff; 71 pRgnInfo->endIndex = 0; 72 } else { 73 pRgnInfo->bounds.x1 = (*env)->GetIntField(env, region, loxID); 74 pRgnInfo->bounds.y1 = (*env)->GetIntField(env, region, loyID); 75 pRgnInfo->bounds.x2 = (*env)->GetIntField(env, region, hixID); 76 pRgnInfo->bounds.y2 = (*env)->GetIntField(env, region, hiyID); 77 pRgnInfo->endIndex = (*env)->GetIntField(env, region, endIndexID); 78 } 79 pRgnInfo->bands = (Region_IsRectangular(pRgnInfo) 80 ? NULL 81 : (*env)->GetObjectField(env, region, bandsID)); 82 return 0; 83} 84 85JNIEXPORT void JNICALL 86Region_GetBounds(JNIEnv *env, jobject region, SurfaceDataBounds *b) 87{ 88 if (JNU_IsNull(env, region)) { 89 b->x1 = b->y1 = 0x80000000; 90 b->x2 = b->y2 = 0x7fffffff; 91 } else { 92 b->x1 = (*env)->GetIntField(env, region, loxID); 93 b->y1 = (*env)->GetIntField(env, region, loyID); 94 b->x2 = (*env)->GetIntField(env, region, hixID); 95 b->y2 = (*env)->GetIntField(env, region, hiyID); 96 } 97} 98 99JNIEXPORT void JNICALL 100Region_StartIteration(JNIEnv *env, RegionData *pRgnInfo) 101{ 102 pRgnInfo->pBands = 103 (Region_IsRectangular(pRgnInfo) 104 ? NULL 105 : (*env)->GetPrimitiveArrayCritical(env, pRgnInfo->bands, 0)); 106 pRgnInfo->index = 0; 107 pRgnInfo->numrects = 0; 108} 109 110JNIEXPORT jint JNICALL 111Region_CountIterationRects(RegionData *pRgnInfo) 112{ 113 jint totalrects; 114 if (Region_IsEmpty(pRgnInfo)) { 115 totalrects = 0; 116 } else if (Region_IsRectangular(pRgnInfo)) { 117 totalrects = 1; 118 } else { 119 jint *pBands = pRgnInfo->pBands; 120 int index = 0; 121 totalrects = 0; 122 while (index < pRgnInfo->endIndex) { 123 jint xy1 = pBands[index++]; 124 jint xy2 = pBands[index++]; 125 jint numrects = pBands[index++]; 126 if (xy1 >= pRgnInfo->bounds.y2) { 127 break; 128 } 129 if (xy2 > pRgnInfo->bounds.y1) { 130 while (numrects > 0) { 131 xy1 = pBands[index++]; 132 xy2 = pBands[index++]; 133 numrects--; 134 if (xy1 >= pRgnInfo->bounds.x2) { 135 break; 136 } 137 if (xy2 > pRgnInfo->bounds.x1) { 138 totalrects++; 139 } 140 } 141 } 142 index += numrects * 2; 143 } 144 } 145 return totalrects; 146} 147 148JNIEXPORT jint JNICALL 149Region_NextIteration(RegionData *pRgnInfo, SurfaceDataBounds *pSpan) 150{ 151 jint index = pRgnInfo->index; 152 if (Region_IsRectangular(pRgnInfo)) { 153 if (index > 0 || Region_IsEmpty(pRgnInfo)) { 154 return 0; 155 } 156 pSpan->x1 = pRgnInfo->bounds.x1; 157 pSpan->x2 = pRgnInfo->bounds.x2; 158 pSpan->y1 = pRgnInfo->bounds.y1; 159 pSpan->y2 = pRgnInfo->bounds.y2; 160 index = 1; 161 } else { 162 jint *pBands = pRgnInfo->pBands; 163 jint xy1, xy2; 164 jint numrects = pRgnInfo->numrects; 165 while (JNI_TRUE) { 166 if (numrects <= 0) { 167 if (index >= pRgnInfo->endIndex) { 168 return 0; 169 } 170 xy1 = pBands[index++]; 171 if (xy1 >= pRgnInfo->bounds.y2) { 172 return 0; 173 } 174 if (xy1 < pRgnInfo->bounds.y1) { 175 xy1 = pRgnInfo->bounds.y1; 176 } 177 xy2 = pBands[index++]; 178 numrects = pBands[index++]; 179 if (xy2 > pRgnInfo->bounds.y2) { 180 xy2 = pRgnInfo->bounds.y2; 181 } 182 if (xy2 <= xy1) { 183 index += numrects * 2; 184 numrects = 0; 185 continue; 186 } 187 pSpan->y1 = xy1; 188 pSpan->y2 = xy2; 189 } 190 xy1 = pBands[index++]; 191 xy2 = pBands[index++]; 192 numrects--; 193 if (xy1 >= pRgnInfo->bounds.x2) { 194 index += numrects * 2; 195 numrects = 0; 196 continue; 197 } 198 if (xy1 < pRgnInfo->bounds.x1) { 199 xy1 = pRgnInfo->bounds.x1; 200 } 201 if (xy2 > pRgnInfo->bounds.x2) { 202 xy2 = pRgnInfo->bounds.x2; 203 } 204 if (xy2 > xy1) { 205 pSpan->x1 = xy1; 206 pSpan->x2 = xy2; 207 break; 208 } 209 } 210 pRgnInfo->numrects = numrects; 211 } 212 pRgnInfo->index = index; 213 return 1; 214} 215 216JNIEXPORT void JNICALL 217Region_EndIteration(JNIEnv *env, RegionData *pRgnInfo) 218{ 219 if (pRgnInfo->endIndex != 0) { 220 (*env)->ReleasePrimitiveArrayCritical(env, pRgnInfo->bands, 221 pRgnInfo->pBands, JNI_ABORT); 222 } 223} 224 225/* 226 * The code was extracted from 227 * src/solaris/native/sun/java2d/x11/X11SurfaceData.c 228 * XSetClip() method. 229 * 230 * If the region is null, the shape is considered to be 231 * a rectangle (x1, y1, x2-x1, y2-y1). 232 * 233 * The *pRect must point to a buffer of initialBufferSize 234 * rectangles. If there're more than initialBufferSize 235 * rectangles in the region, the buffer is reallocated 236 * and its pointer is being stored at the *pRect. Using 237 * this practice we may use a small local (on the stack) 238 * buffer and avoid allocating/freeing a memory if we 239 * operate simple regions. 240 */ 241JNIEXPORT int JNICALL 242RegionToYXBandedRectangles(JNIEnv *env, 243 jint x1, jint y1, jint x2, jint y2, jobject region, 244 RECT_T ** pRect, unsigned int initialBufferSize) 245{ 246 RegionData clipInfo; 247 SurfaceDataBounds span; 248 int i, numrects; 249 250 if (region == NULL) { 251 if (x2 <= x1 || y2 <= y1) { 252 /* empty clip, disable rendering */ 253 numrects = 0; 254 } else { 255 RECT_SET(**pRect, x1, y1, x2 - x1, y2 - y1); 256 numrects = 1; 257 } 258 } else { 259 if (Region_GetInfo(env, region, &clipInfo)) { 260 /* return; REMIND: What to do here? */ 261 } 262 Region_StartIteration(env, &clipInfo); 263 if ((*env)->ExceptionCheck(env)) { 264 return 0; 265 } 266 267 numrects = Region_CountIterationRects(&clipInfo); 268 if ((unsigned long)numrects > initialBufferSize) { 269 *pRect = (RECT_T *) SAFE_SIZE_ARRAY_ALLOC(malloc, numrects, sizeof(RECT_T)); 270 if (*pRect == NULL) { 271 Region_EndIteration(env, &clipInfo); 272 JNU_ThrowOutOfMemoryError(env, 273 "Can't allocate shape region memory"); 274 return 0; 275 } 276 } 277 for (i = 0; Region_NextIteration(&clipInfo, &span); i++) { 278 RECT_SET((*pRect)[i], span.x1, span.y1, span.x2 - span.x1, span.y2 - span.y1); 279 } 280 Region_EndIteration(env, &clipInfo); 281 } 282 283 return numrects; 284} 285