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