1/*
2 * Copyright (c) 1997, 2014, 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 <string.h>
27
28#include "jni.h"
29#include "jni_util.h"
30#include "awt_parseImage.h"
31#include "imageInitIDs.h"
32#include "sun_awt_image_ImageRepresentation.h"
33
34static int compareLUTs(unsigned int *lut1, int numLut1, int transIdx,
35 unsigned int *lut2, int numLut2, unsigned char *cvtLut,
36 int *retNumLut1, int *retTransIdx, int *jniFlagP);
37
38static int findIdx(unsigned int rgb, unsigned int *lut, int numLut1);
39
40#define ALPHA_MASK 0xff000000
41#ifndef FALSE
42# define FALSE 0
43#endif
44#ifndef TRUE
45# define TRUE 1
46#endif
47
48#define CHECK_STRIDE(yy, hh, ss) \
49 if ((ss) != 0) { \
50 int limit = 0x7fffffff / ((ss) > 0 ? (ss) : -(ss)); \
51 if (limit < (yy) || limit < ((yy) + (hh) - 1)) { \
52 /* integer oveflow */ \
53 return JNI_FALSE; \
54 } \
55 } \
56
57#define CHECK_SRC() \
58 do { \
59 int pixeloffset; \
60 if (off < 0 || off >= srcDataLength) { \
61 return JNI_FALSE; \
62 } \
63 CHECK_STRIDE(0, h, scansize); \
64 \
65 /* check scansize */ \
66 pixeloffset = scansize * (h - 1); \
67 if ((w - 1) > (0x7fffffff - pixeloffset)) { \
68 return JNI_FALSE; \
69 } \
70 pixeloffset += (w - 1); \
71 \
72 if (off > (0x7fffffff - pixeloffset)) { \
73 return JNI_FALSE; \
74 } \
75 } while (0) \
76
77#define CHECK_DST(xx, yy) \
78 do { \
79 int soffset = (yy) * sStride; \
80 int poffset = (xx) * pixelStride; \
81 if (poffset > (0x7fffffff - soffset)) { \
82 return JNI_FALSE; \
83 } \
84 poffset += soffset; \
85 if (dstDataOff > (0x7fffffff - poffset)) { \
86 return JNI_FALSE; \
87 } \
88 poffset += dstDataOff; \
89 \
90 if (poffset < 0 || poffset >= dstDataLength) { \
91 return JNI_FALSE; \
92 } \
93 } while (0) \
94
95static jfieldID s_JnumSrcLUTID;
96static jfieldID s_JsrcLUTtransIndexID;
97
98JNIEXPORT void JNICALL
99Java_sun_awt_image_ImageRepresentation_initIDs(JNIEnv *env, jclass cls) {
100 CHECK_NULL(s_JnumSrcLUTID = (*env)->GetFieldID(env, cls, "numSrcLUT", "I"));
101 CHECK_NULL(s_JsrcLUTtransIndexID = (*env)->GetFieldID(env, cls,
102 "srcLUTtransIndex", "I"));
103}
104
105/*
106 * This routine is used to draw ICM pixels into a default color model
107 */
108JNIEXPORT jboolean JNICALL
109Java_sun_awt_image_ImageRepresentation_setICMpixels(JNIEnv *env, jclass cls,
110 jint x, jint y, jint w,
111 jint h, jintArray jlut,
112 jbyteArray jpix, jint off,
113 jint scansize,
114 jobject jict)
115{
116 unsigned char *srcData = NULL;
117 jint srcDataLength;
118 int *dstData;
119 jint dstDataLength;
120 jint dstDataOff;
121 int *dstP, *dstyP;
122 unsigned char *srcyP, *srcP;
123 int *srcLUT = NULL;
124 int yIdx, xIdx;
125 int sStride;
126 int *cOffs;
127 int pixelStride;
128 jobject joffs = NULL;
129 jobject jdata = NULL;
130
131 if (JNU_IsNull(env, jlut)) {
132 JNU_ThrowNullPointerException(env, "NullPointerException");
133 return JNI_FALSE;
134 }
135
136 if (JNU_IsNull(env, jpix)) {
137 JNU_ThrowNullPointerException(env, "NullPointerException");
138 return JNI_FALSE;
139 }
140
141 if (x < 0 || w < 1 || (0x7fffffff - x) < w) {
142 return JNI_FALSE;
143 }
144
145 if (y < 0 || h < 1 || (0x7fffffff - y) < h) {
146 return JNI_FALSE;
147 }
148
149 sStride = (*env)->GetIntField(env, jict, g_ICRscanstrID);
150 pixelStride = (*env)->GetIntField(env, jict, g_ICRpixstrID);
151 joffs = (*env)->GetObjectField(env, jict, g_ICRdataOffsetsID);
152 jdata = (*env)->GetObjectField(env, jict, g_ICRdataID);
153
154 if (JNU_IsNull(env, jdata)) {
155 /* no destination buffer */
156 return JNI_FALSE;
157 }
158
159 if (JNU_IsNull(env, joffs) || (*env)->GetArrayLength(env, joffs) < 1) {
160 /* invalid data offstes in raster */
161 return JNI_FALSE;
162 }
163
164 srcDataLength = (*env)->GetArrayLength(env, jpix);
165 dstDataLength = (*env)->GetArrayLength(env, jdata);
166
167 cOffs = (int *) (*env)->GetPrimitiveArrayCritical(env, joffs, NULL);
168 if (cOffs == NULL) {
169 (*env)->ExceptionClear(env);
170 JNU_ThrowNullPointerException(env, "Null channel offset array");
171 return JNI_FALSE;
172 }
173
174 dstDataOff = cOffs[0];
175
176 /* the offset array is not needed anymore and can be released */
177 (*env)->ReleasePrimitiveArrayCritical(env, joffs, cOffs, JNI_ABORT);
178 joffs = NULL;
179 cOffs = NULL;
180
181 /* do basic validation: make sure that offsets for
182 * first pixel and for last pixel are safe to calculate and use */
183 CHECK_STRIDE(y, h, sStride);
184 CHECK_STRIDE(x, w, pixelStride);
185
186 CHECK_DST(x, y);
187 CHECK_DST(x + w -1, y + h - 1);
188
189 /* check source array */
190 CHECK_SRC();
191
192 srcLUT = (int *) (*env)->GetPrimitiveArrayCritical(env, jlut, NULL);
193 if (srcLUT == NULL) {
194 (*env)->ExceptionClear(env);
195 JNU_ThrowNullPointerException(env, "Null IndexColorModel LUT");
196 return JNI_FALSE;
197 }
198
199 srcData = (unsigned char *) (*env)->GetPrimitiveArrayCritical(env, jpix,
200 NULL);
201 if (srcData == NULL) {
202 (*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT);
203 (*env)->ExceptionClear(env);
204 JNU_ThrowNullPointerException(env, "Null data array");
205 return JNI_FALSE;
206 }
207
208 dstData = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata, NULL);
209 if (dstData == NULL) {
210 (*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT);
211 (*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT);
212 (*env)->ExceptionClear(env);
213 JNU_ThrowNullPointerException(env, "Null tile data array");
214 return JNI_FALSE;
215 }
216
217 dstyP = dstData + dstDataOff + y*sStride + x*pixelStride;
218 srcyP = srcData + off;
219 for (yIdx = 0; yIdx < h; yIdx++, srcyP += scansize, dstyP+=sStride) {
220 srcP = srcyP;
221 dstP = dstyP;
222 for (xIdx = 0; xIdx < w; xIdx++, dstP+=pixelStride) {
223 *dstP = srcLUT[*srcP++];
224 }
225 }
226
227 /* Release the locked arrays */
228 (*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT);
229 (*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT);
230 (*env)->ReleasePrimitiveArrayCritical(env, jdata, dstData, JNI_ABORT);
231
232 return JNI_TRUE;
233}
234
235JNIEXPORT jboolean JNICALL
236Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls,
237 jint x, jint y, jint w,
238 jint h, jintArray jlut,
239 jint transIdx, jint numLut,
240 jobject jicm,
241 jbyteArray jpix, jint off,
242 jint scansize,
243 jobject jbct, jint dstDataOff)
244{
245 unsigned int *srcLUT = NULL;
246 unsigned int *newLUT = NULL;
247 int sStride;
248 int pixelStride;
249 int mapSize;
250 jobject jdata = NULL;
251 jobject jnewlut = NULL;
252 jint srcDataLength;
253 jint dstDataLength;
254 unsigned char *srcData;
255 unsigned char *dstData;
256 unsigned char *dataP;
257 unsigned char *pixP;
258 int i;
259 int j;
260 int newNumLut;
261 int newTransIdx;
262 int jniFlag = JNI_ABORT;
263 unsigned char *ydataP;
264 unsigned char *ypixP;
265 unsigned char cvtLut[256];
266
267 if (JNU_IsNull(env, jlut)) {
268 JNU_ThrowNullPointerException(env, "NullPointerException");
269 return JNI_FALSE;
270 }
271
272 if (JNU_IsNull(env, jpix)) {
273 JNU_ThrowNullPointerException(env, "NullPointerException");
274 return JNI_FALSE;
275 }
276
277 if (x < 0 || w < 1 || (0x7fffffff - x) < w) {
278 return JNI_FALSE;
279 }
280
281 if (y < 0 || h < 1 || (0x7fffffff - y) < h) {
282 return JNI_FALSE;
283 }
284
285
286 sStride = (*env)->GetIntField(env, jbct, g_BCRscanstrID);
287 pixelStride =(*env)->GetIntField(env, jbct, g_BCRpixstrID);
288 jdata = (*env)->GetObjectField(env, jbct, g_BCRdataID);
289 jnewlut = (*env)->GetObjectField(env, jicm, g_ICMrgbID);
290 mapSize = (*env)->GetIntField(env, jicm, g_ICMmapSizeID);
291
292 if (numLut < 0 || numLut > 256 || mapSize < 0 || mapSize > 256) {
293 /* Ether old or new ICM has a palette that exceeds capacity
294 of byte data type, so we have to convert the image data
295 to default representation.
296 */
297 return JNI_FALSE;
298 }
299
300 if (JNU_IsNull(env, jdata)) {
301 /* no destination buffer */
302 return JNI_FALSE;
303 }
304
305 srcDataLength = (*env)->GetArrayLength(env, jpix);
306 dstDataLength = (*env)->GetArrayLength(env, jdata);
307
308 CHECK_STRIDE(y, h, sStride);
309 CHECK_STRIDE(x, w, pixelStride);
310
311 CHECK_DST(x, y);
312 CHECK_DST(x + w -1, y + h - 1);
313
314 /* check source array */
315 CHECK_SRC();
316
317 srcLUT = (unsigned int *) (*env)->GetPrimitiveArrayCritical(env, jlut,
318 NULL);
319 if (srcLUT == NULL) {
320 /* out of memory error already thrown */
321 return JNI_FALSE;
322 }
323
324 newLUT = (unsigned int *) (*env)->GetPrimitiveArrayCritical(env, jnewlut,
325 NULL);
326 if (newLUT == NULL) {
327 (*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT,
328 JNI_ABORT);
329 /* out of memory error already thrown */
330 return JNI_FALSE;
331 }
332
333 newNumLut = numLut;
334 newTransIdx = transIdx;
335 if (compareLUTs(srcLUT, numLut, transIdx, newLUT, mapSize,
336 cvtLut, &newNumLut, &newTransIdx, &jniFlag) == FALSE) {
337 /* Need to convert to ICR */
338 (*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT,
339 JNI_ABORT);
340 (*env)->ReleasePrimitiveArrayCritical(env, jnewlut, newLUT, JNI_ABORT);
341 return JNI_FALSE;
342 }
343
344 /* Don't need these any more */
345 (*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, jniFlag);
346 (*env)->ReleasePrimitiveArrayCritical(env, jnewlut, newLUT, JNI_ABORT);
347
348 if (newNumLut != numLut) {
349 /* Need to write back new number of entries in lut */
350 (*env)->SetIntField(env, cls, s_JnumSrcLUTID, newNumLut);
351 }
352
353 if (newTransIdx != transIdx) {
354 (*env)->SetIntField(env, cls, s_JsrcLUTtransIndexID, newTransIdx);
355 }
356
357 srcData = (unsigned char *) (*env)->GetPrimitiveArrayCritical(env, jpix,
358 NULL);
359 if (srcData == NULL) {
360 /* out of memory error already thrown */
361 return JNI_FALSE;
362 }
363
364 dstData = (unsigned char *) (*env)->GetPrimitiveArrayCritical(env, jdata,
365 NULL);
366 if (dstData == NULL) {
367 (*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT);
368 /* out of memory error already thrown */
369 return JNI_FALSE;
370 }
371
372 ydataP = dstData + dstDataOff + y*sStride + x*pixelStride;
373 ypixP = srcData + off;
374
375 for (i=0; i < h; i++) {
376 dataP = ydataP;
377 pixP = ypixP;
378 for (j=0; j < w; j++) {
379 *dataP = cvtLut[*pixP];
380 dataP += pixelStride;
381 pixP++;
382 }
383 ydataP += sStride;
384 ypixP += scansize;
385 }
386
387 (*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT);
388 (*env)->ReleasePrimitiveArrayCritical(env, jdata, dstData, JNI_ABORT);
389
390 return JNI_TRUE;
391}
392
393static int compareLUTs(unsigned int *lut1, int numLut1, int transIdx,
394 unsigned int *lut2, int numLut2, unsigned char *cvtLut,
395 int *retNumLut1, int *retTransIdx, int *jniFlagP)
396{
397 int i;
398 int idx;
399 int newTransIdx = -1;
400 unsigned int rgb;
401 int changed = FALSE;
402 int maxSize = (numLut1 > numLut2 ? numLut1 : numLut2);
403
404 *jniFlagP = JNI_ABORT;
405
406 for (i=0; i < maxSize; i++) {
407 cvtLut[i] = i;
408 }
409
410 for (i=0; i < numLut2; i++) {
411 /* If this slot in new palette is different from the
412 * same slot in current palette, then we try to find
413 * this color in other slots. On failure, add this color
414 * to current palette.
415 */
416 if ((i >= numLut1) ||
417 (lut1[i] != lut2[i]))
418 {
419 rgb = lut2[i];
420 /* Transparent */
421 if ((rgb & ALPHA_MASK) == 0) {
422 if (transIdx == -1) {
423 if (numLut1 < 256) {
424 cvtLut[i] = numLut1;
425 newTransIdx = i;
426 transIdx = i;
427 numLut1++;
428 changed = TRUE;
429 }
430 else {
431 return FALSE;
432 }
433 }
434 cvtLut[i] = transIdx;
435 }
436 else {
437 if ((idx = findIdx(rgb, lut1, numLut1)) == -1) {
438 if (numLut1 < 256) {
439 lut1[numLut1] = rgb;
440 cvtLut[i] = numLut1;
441 numLut1++;
442 changed = TRUE;
443 }
444 else {
445 /* Bad news... need to convert image */
446 return FALSE;
447 }
448 } else {
449 cvtLut[i] = idx;
450 }
451 }
452 }
453 }
454
455 if (changed) {
456 *jniFlagP = 0;
457 *retNumLut1 = numLut1;
458 if (newTransIdx != -1) {
459 *retTransIdx = newTransIdx;
460 }
461 }
462 return TRUE;
463}
464
465static int findIdx(unsigned int rgb, unsigned int *lut, int numLut) {
466 int i;
467
468 if ((rgb&0xff000000)==0) {
469 for (i=0; i < numLut; i++) {
470 if ((lut[i]&0xff000000)==0) return i;
471 }
472 }
473 else {
474 for (i=0; i < numLut; i++) {
475 if (lut[i] == rgb) return i;
476 }
477 }
478 return -1;
479}
480