blob: 0a7a07a2e72daf7a3158455dfe8418b51a1b1d05 [file] [log] [blame]
/*
* 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;
}