| /* |
| * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| #include <stdlib.h> |
| |
| #include "jni_util.h" |
| |
| #include "Region.h" |
| |
| static jfieldID endIndexID; |
| static jfieldID bandsID; |
| static jfieldID loxID; |
| static jfieldID loyID; |
| static jfieldID hixID; |
| static jfieldID hiyID; |
| |
| #define InitField(var, env, jcl, name, type) \ |
| do { \ |
| var = (*env)->GetFieldID(env, jcl, name, type); \ |
| if (var == NULL) { \ |
| return; \ |
| } \ |
| } while (0) |
| |
| /* |
| * Class: sun_java2d_pipe_Region |
| * Method: initIDs |
| * Signature: ()V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_java2d_pipe_Region_initIDs(JNIEnv *env, jclass reg) |
| { |
| InitField(endIndexID, env, reg, "endIndex", "I"); |
| InitField(bandsID, env, reg, "bands", "[I"); |
| |
| InitField(loxID, env, reg, "lox", "I"); |
| InitField(loyID, env, reg, "loy", "I"); |
| InitField(hixID, env, reg, "hix", "I"); |
| InitField(hiyID, env, reg, "hiy", "I"); |
| } |
| |
| JNIEXPORT jint JNICALL |
| Region_GetInfo(JNIEnv *env, jobject region, RegionData *pRgnInfo) |
| { |
| if (JNU_IsNull(env, region)) { |
| pRgnInfo->bounds.x1 = pRgnInfo->bounds.y1 = 0x80000000; |
| pRgnInfo->bounds.x2 = pRgnInfo->bounds.y2 = 0x7fffffff; |
| pRgnInfo->endIndex = 0; |
| } else { |
| pRgnInfo->bounds.x1 = (*env)->GetIntField(env, region, loxID); |
| pRgnInfo->bounds.y1 = (*env)->GetIntField(env, region, loyID); |
| pRgnInfo->bounds.x2 = (*env)->GetIntField(env, region, hixID); |
| pRgnInfo->bounds.y2 = (*env)->GetIntField(env, region, hiyID); |
| pRgnInfo->endIndex = (*env)->GetIntField(env, region, endIndexID); |
| } |
| pRgnInfo->bands = (Region_IsRectangular(pRgnInfo) |
| ? NULL |
| : (*env)->GetObjectField(env, region, bandsID)); |
| return 0; |
| } |
| |
| JNIEXPORT void JNICALL |
| Region_GetBounds(JNIEnv *env, jobject region, SurfaceDataBounds *b) |
| { |
| if (JNU_IsNull(env, region)) { |
| b->x1 = b->y1 = 0x80000000; |
| b->x2 = b->y2 = 0x7fffffff; |
| } else { |
| b->x1 = (*env)->GetIntField(env, region, loxID); |
| b->y1 = (*env)->GetIntField(env, region, loyID); |
| b->x2 = (*env)->GetIntField(env, region, hixID); |
| b->y2 = (*env)->GetIntField(env, region, hiyID); |
| } |
| } |
| |
| JNIEXPORT void JNICALL |
| Region_StartIteration(JNIEnv *env, RegionData *pRgnInfo) |
| { |
| pRgnInfo->pBands = |
| (Region_IsRectangular(pRgnInfo) |
| ? NULL |
| : (*env)->GetPrimitiveArrayCritical(env, pRgnInfo->bands, 0)); |
| pRgnInfo->index = 0; |
| pRgnInfo->numrects = 0; |
| } |
| |
| JNIEXPORT jint JNICALL |
| Region_CountIterationRects(RegionData *pRgnInfo) |
| { |
| jint totalrects; |
| if (Region_IsEmpty(pRgnInfo)) { |
| totalrects = 0; |
| } else if (Region_IsRectangular(pRgnInfo)) { |
| totalrects = 1; |
| } else { |
| jint *pBands = pRgnInfo->pBands; |
| int index = 0; |
| totalrects = 0; |
| while (index < pRgnInfo->endIndex) { |
| jint xy1 = pBands[index++]; |
| jint xy2 = pBands[index++]; |
| jint numrects = pBands[index++]; |
| if (xy1 >= pRgnInfo->bounds.y2) { |
| break; |
| } |
| if (xy2 > pRgnInfo->bounds.y1) { |
| while (numrects > 0) { |
| xy1 = pBands[index++]; |
| xy2 = pBands[index++]; |
| numrects--; |
| if (xy1 >= pRgnInfo->bounds.x2) { |
| break; |
| } |
| if (xy2 > pRgnInfo->bounds.x1) { |
| totalrects++; |
| } |
| } |
| } |
| index += numrects * 2; |
| } |
| } |
| return totalrects; |
| } |
| |
| JNIEXPORT jint JNICALL |
| Region_NextIteration(RegionData *pRgnInfo, SurfaceDataBounds *pSpan) |
| { |
| jint index = pRgnInfo->index; |
| if (Region_IsRectangular(pRgnInfo)) { |
| if (index > 0 || Region_IsEmpty(pRgnInfo)) { |
| return 0; |
| } |
| pSpan->x1 = pRgnInfo->bounds.x1; |
| pSpan->x2 = pRgnInfo->bounds.x2; |
| pSpan->y1 = pRgnInfo->bounds.y1; |
| pSpan->y2 = pRgnInfo->bounds.y2; |
| index = 1; |
| } else { |
| jint *pBands = pRgnInfo->pBands; |
| jint xy1, xy2; |
| jint numrects = pRgnInfo->numrects; |
| while (JNI_TRUE) { |
| if (numrects <= 0) { |
| if (index >= pRgnInfo->endIndex) { |
| return 0; |
| } |
| xy1 = pBands[index++]; |
| if (xy1 >= pRgnInfo->bounds.y2) { |
| return 0; |
| } |
| if (xy1 < pRgnInfo->bounds.y1) { |
| xy1 = pRgnInfo->bounds.y1; |
| } |
| xy2 = pBands[index++]; |
| numrects = pBands[index++]; |
| if (xy2 > pRgnInfo->bounds.y2) { |
| xy2 = pRgnInfo->bounds.y2; |
| } |
| if (xy2 <= xy1) { |
| index += numrects * 2; |
| numrects = 0; |
| continue; |
| } |
| pSpan->y1 = xy1; |
| pSpan->y2 = xy2; |
| } |
| xy1 = pBands[index++]; |
| xy2 = pBands[index++]; |
| numrects--; |
| if (xy1 >= pRgnInfo->bounds.x2) { |
| index += numrects * 2; |
| numrects = 0; |
| continue; |
| } |
| if (xy1 < pRgnInfo->bounds.x1) { |
| xy1 = pRgnInfo->bounds.x1; |
| } |
| if (xy2 > pRgnInfo->bounds.x2) { |
| xy2 = pRgnInfo->bounds.x2; |
| } |
| if (xy2 > xy1) { |
| pSpan->x1 = xy1; |
| pSpan->x2 = xy2; |
| break; |
| } |
| } |
| pRgnInfo->numrects = numrects; |
| } |
| pRgnInfo->index = index; |
| return 1; |
| } |
| |
| JNIEXPORT void JNICALL |
| Region_EndIteration(JNIEnv *env, RegionData *pRgnInfo) |
| { |
| if (pRgnInfo->endIndex != 0) { |
| (*env)->ReleasePrimitiveArrayCritical(env, pRgnInfo->bands, |
| pRgnInfo->pBands, JNI_ABORT); |
| } |
| } |
| |
| /* |
| * The code was extracted from |
| * src/solaris/native/sun/java2d/x11/X11SurfaceData.c |
| * XSetClip() method. |
| * |
| * If the region is null, the shape is considered to be |
| * a rectangle (x1, y1, x2-x1, y2-y1). |
| * |
| * The *pRect must point to a buffer of initialBufferSize |
| * rectangles. If there're more than initialBufferSize |
| * rectangles in the region, the buffer is reallocated |
| * and its pointer is being stored at the *pRect. Using |
| * this practice we may use a small local (on the stack) |
| * buffer and avoid allocating/freeing a memory if we |
| * operate simple regions. |
| */ |
| JNIEXPORT int JNICALL |
| RegionToYXBandedRectangles(JNIEnv *env, |
| jint x1, jint y1, jint x2, jint y2, jobject region, |
| RECT_T ** pRect, unsigned int initialBufferSize) |
| { |
| RegionData clipInfo; |
| SurfaceDataBounds span; |
| int i, numrects; |
| |
| if (region == NULL) { |
| if (x2 <= x1 || y2 <= y1) { |
| /* empty clip, disable rendering */ |
| numrects = 0; |
| } else { |
| RECT_SET(**pRect, x1, y1, x2 - x1, y2 - y1); |
| numrects = 1; |
| } |
| } else { |
| if (Region_GetInfo(env, region, &clipInfo)) { |
| /* return; REMIND: What to do here? */ |
| } |
| Region_StartIteration(env, &clipInfo); |
| numrects = Region_CountIterationRects(&clipInfo); |
| if (numrects > initialBufferSize) { |
| *pRect = (RECT_T *) malloc(numrects * sizeof(RECT_T)); |
| if (*pRect == NULL) { |
| Region_EndIteration(env, &clipInfo); |
| JNU_ThrowOutOfMemoryError(env, |
| "Can't allocate shape region memory"); |
| return 0; |
| } |
| } |
| for (i = 0; Region_NextIteration(&clipInfo, &span); i++) { |
| RECT_SET((*pRect)[i], span.x1, span.y1, span.x2 - span.x1, span.y2 - span.y1); |
| } |
| Region_EndIteration(env, &clipInfo); |
| } |
| |
| return numrects; |
| } |