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
Java_sun_awt_image_ImageRepresentation_initIDs(JNIEnv * env,jclass cls)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
Java_sun_awt_image_ImageRepresentation_setICMpixels(JNIEnv * env,jclass cls,jint x,jint y,jint w,jint h,jintArray jlut,jbyteArray jpix,jint off,jint scansize,jobject jict)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
Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv * env,jclass cls,jint x,jint y,jint w,jint h,jintArray jlut,jint transIdx,jint numLut,jobject jicm,jbyteArray jpix,jint off,jint scansize,jobject jbct,jint dstDataOff)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 
compareLUTs(unsigned int * lut1,int numLut1,int transIdx,unsigned int * lut2,int numLut2,unsigned char * cvtLut,int * retNumLut1,int * retTransIdx,int * jniFlagP)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 
findIdx(unsigned int rgb,unsigned int * lut,int numLut)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