1 /*
   2  * Copyright (c) 1998, 2000, 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 #include <string.h>
  28 #include <math.h>
  29 
  30 #include "jni.h"
  31 #include "jni_util.h"
  32 
  33 #include "sun_java2d_pipe_SpanClipRenderer.h"
  34 
  35 jfieldID pBandsArrayID;
  36 jfieldID pEndIndexID;
  37 jfieldID pRegionID;
  38 jfieldID pCurIndexID;
  39 jfieldID pNumXbandsID;
  40 
  41 JNIEXPORT void JNICALL
  42 Java_sun_java2d_pipe_SpanClipRenderer_initIDs
  43     (JNIEnv *env, jclass src, jclass rc, jclass ric)
  44 {
  45     /* Region fields */
  46     pBandsArrayID = (*env)->GetFieldID(env, rc, "bands", "[I");
  47     pEndIndexID = (*env)->GetFieldID(env, rc, "endIndex", "I");
  48 
  49     /* RegionIterator fields */
  50     pRegionID = (*env)->GetFieldID(env, ric, "region",
  51                                    "Lsun/java2d/pipe/Region;");
  52     pCurIndexID = (*env)->GetFieldID(env, ric, "curIndex", "I");
  53     pNumXbandsID = (*env)->GetFieldID(env, ric, "numXbands", "I");
  54 
  55     if((pBandsArrayID == NULL)
  56        || (pEndIndexID == NULL)
  57        || (pRegionID == NULL)
  58        || (pCurIndexID == NULL)
  59        || (pNumXbandsID == NULL))
  60     {
  61         JNU_ThrowInternalError(env, "NULL field ID");
  62     }
  63 }
  64 
  65 static void
  66 fill(jbyte *alpha, jint offset, jint tsize,
  67      jint x, jint y, jint w, jint h, jbyte value)
  68 {
  69     alpha += offset + y * tsize + x;
  70     tsize -= w;
  71     while (--h >= 0) {
  72         for (x = 0; x < w; x++) {
  73             *alpha++ = value;
  74         }
  75         alpha += tsize;
  76     }
  77 }
  78 
  79 static jboolean
  80 nextYRange(jint *box, jint *bands, jint endIndex,
  81            jint *pCurIndex, jint *pNumXbands)
  82 {
  83     jint curIndex = *pCurIndex;
  84     jint numXbands = *pNumXbands;
  85     jboolean ret;
  86 
  87     curIndex += numXbands * 2;
  88     ret = (curIndex + 3 < endIndex);
  89     if (ret) {
  90         box[1] = bands[curIndex++];
  91         box[3] = bands[curIndex++];
  92         numXbands = bands[curIndex++];
  93     } else {
  94         numXbands = 0;
  95     }
  96     *pCurIndex = curIndex;
  97     *pNumXbands = numXbands;
  98     return ret;
  99 }
 100 
 101 static jboolean
 102 nextXBand(jint *box, jint *bands, jint endIndex,
 103           jint *pCurIndex, jint *pNumXbands)
 104 {
 105     jint curIndex = *pCurIndex;
 106     jint numXbands = *pNumXbands;
 107 
 108     if (numXbands <= 0 || curIndex + 2 > endIndex) {
 109         return JNI_FALSE;
 110     }
 111     numXbands--;
 112     box[0] = bands[curIndex++];
 113     box[2] = bands[curIndex++];
 114 
 115     *pCurIndex = curIndex;
 116     *pNumXbands = numXbands;
 117     return JNI_TRUE;
 118 }
 119 
 120 JNIEXPORT void JNICALL
 121 Java_sun_java2d_pipe_SpanClipRenderer_fillTile
 122     (JNIEnv *env, jobject sr, jobject ri,
 123      jbyteArray alphaTile, jint offset, jint tsize, jintArray boxArray)
 124 {
 125     jbyte *alpha;
 126     jint *box;
 127     jint w, h;
 128     jsize alphalen;
 129 
 130     if ((*env)->GetArrayLength(env, boxArray) < 4) {
 131         JNU_ThrowArrayIndexOutOfBoundsException(env, "band array");
 132     }
 133     alphalen = (*env)->GetArrayLength(env, alphaTile);
 134 
 135     box = (*env)->GetPrimitiveArrayCritical(env, boxArray, 0);
 136 
 137     w = box[2] - box[0];
 138     h = box[3] - box[1];
 139 
 140     if (alphalen < offset || (alphalen - offset) / tsize < h) {
 141         (*env)->ReleasePrimitiveArrayCritical(env, boxArray, box, 0);
 142         JNU_ThrowArrayIndexOutOfBoundsException(env, "alpha tile array");
 143     }
 144 
 145     alpha = (*env)->GetPrimitiveArrayCritical(env, alphaTile, 0);
 146 
 147     fill(alpha, offset, tsize, 0, 0, w, h, (jbyte) 0xff);
 148 
 149     (*env)->ReleasePrimitiveArrayCritical(env, alphaTile, alpha, 0);
 150     (*env)->ReleasePrimitiveArrayCritical(env, boxArray, box, 0);
 151 
 152     Java_sun_java2d_pipe_SpanClipRenderer_eraseTile(env, sr, ri,
 153                                                     alphaTile, offset, tsize,
 154                                                     boxArray);
 155 }
 156 
 157 JNIEXPORT void JNICALL
 158 Java_sun_java2d_pipe_SpanClipRenderer_eraseTile
 159     (JNIEnv *env, jobject sr, jobject ri,
 160      jbyteArray alphaTile, jint offset, jint tsize, jintArray boxArray)
 161 {
 162     jobject region;
 163     jintArray bandsArray;
 164     jint *bands;
 165     jbyte *alpha;
 166     jint *box;
 167     jint endIndex;
 168     jint curIndex;
 169     jint saveCurIndex;
 170     jint numXbands;
 171     jint saveNumXbands;
 172     jint lox;
 173     jint loy;
 174     jint hix;
 175     jint hiy;
 176     jint firstx;
 177     jint firsty;
 178     jint lastx;
 179     jint lasty;
 180     jint curx;
 181     jsize alphalen;
 182 
 183     if ((*env)->GetArrayLength(env, boxArray) < 4) {
 184         JNU_ThrowArrayIndexOutOfBoundsException(env, "band array");
 185     }
 186     alphalen = (*env)->GetArrayLength(env, alphaTile);
 187 
 188     saveCurIndex = (*env)->GetIntField(env, ri, pCurIndexID);
 189     saveNumXbands = (*env)->GetIntField(env, ri, pNumXbandsID);
 190     region = (*env)->GetObjectField(env, ri, pRegionID);
 191     bandsArray = (*env)->GetObjectField(env, region, pBandsArrayID);
 192     endIndex = (*env)->GetIntField(env, region, pEndIndexID);
 193 
 194     if (endIndex > (*env)->GetArrayLength(env, bandsArray)) {
 195         endIndex = (*env)->GetArrayLength(env, bandsArray);
 196     }
 197 
 198     box = (*env)->GetPrimitiveArrayCritical(env, boxArray, 0);
 199 
 200     lox = box[0];
 201     loy = box[1];
 202     hix = box[2];
 203     hiy = box[3];
 204 
 205     if (alphalen < offset ||
 206         alphalen < offset + (hix-lox) ||
 207         (alphalen - offset - (hix-lox)) / tsize < (hiy - loy - 1)) {
 208         (*env)->ReleasePrimitiveArrayCritical(env, boxArray, box, 0);
 209         JNU_ThrowArrayIndexOutOfBoundsException(env, "alpha tile array");
 210     }
 211 
 212     bands = (*env)->GetPrimitiveArrayCritical(env, bandsArray, 0);
 213     alpha = (*env)->GetPrimitiveArrayCritical(env, alphaTile, 0);
 214 
 215     curIndex = saveCurIndex;
 216     numXbands = saveNumXbands;
 217     firsty = hiy;
 218     lasty = hiy;
 219     firstx = hix;
 220     lastx = lox;
 221 
 222     while (nextYRange(box, bands, endIndex, &curIndex, &numXbands)) {
 223         if (box[3] <= loy) {
 224             saveNumXbands = numXbands;
 225             saveCurIndex = curIndex;
 226             continue;
 227         }
 228         if (box[1] >= hiy) {
 229             break;
 230         }
 231         if (box[1] < loy) {
 232             box[1] = loy;
 233         }
 234         if (box[3] > hiy) {
 235             box[3] = hiy;
 236         }
 237         curx = lox;
 238         while (nextXBand(box, bands, endIndex, &curIndex, &numXbands)) {
 239             if (box[2] <= lox) {
 240                 continue;
 241             }
 242             if (box[0] >= hix) {
 243                 break;
 244             }
 245             if (box[0] < lox) {
 246                 box[0] = lox;
 247             }
 248             if (lasty < box[1]) {
 249                 fill(alpha, offset, tsize,
 250                      0, lasty - loy,
 251                      hix - lox, box[1] - lasty, 0);
 252             }
 253             lasty = box[3];
 254             if (firstx > box[0]) {
 255                 firstx = box[0];
 256             }
 257             if (curx < box[0]) {
 258                 fill(alpha, offset, tsize,
 259                      curx - lox, box[1] - loy,
 260                      box[0] - curx, box[3] - box[1], 0);
 261             }
 262             curx = box[2];
 263             if (curx >= hix) {
 264                 curx = hix;
 265                 break;
 266             }
 267         }
 268         if (curx > lox) {
 269             if (curx < hix) {
 270                 fill(alpha, offset, tsize,
 271                      curx - lox, box[1] - loy,
 272                      hix - curx, box[3] - box[1], 0);
 273             }
 274             if (firsty > box[1]) {
 275                 firsty = box[1];
 276             }
 277         }
 278         if (lastx < curx) {
 279             lastx = curx;
 280         }
 281     }
 282 
 283     box[0] = firstx;
 284     box[1] = firsty;
 285     box[2] = lastx;
 286     box[3] = lasty;
 287 
 288     (*env)->ReleasePrimitiveArrayCritical(env, alphaTile, alpha, 0);
 289     (*env)->ReleasePrimitiveArrayCritical(env, bandsArray, bands, 0);
 290     (*env)->ReleasePrimitiveArrayCritical(env, boxArray, box, 0);
 291 
 292     (*env)->SetIntField(env, ri, pCurIndexID, saveCurIndex);
 293     (*env)->SetIntField(env, ri, pNumXbandsID, saveNumXbands);
 294 }