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 | |
34 | static 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 | |
38 | static 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 | |
95 | static jfieldID s_JnumSrcLUTID; |
96 | static jfieldID s_JsrcLUTtransIndexID; |
97 | |
98 | JNIEXPORT void JNICALL |
99 | Java_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 | */ |
108 | JNIEXPORT jboolean JNICALL |
109 | Java_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 | |
235 | JNIEXPORT jboolean JNICALL |
236 | Java_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 | |
393 | static 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 | |
465 | static 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 | |