|
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 } |