Path: blob/master/src/java.desktop/share/native/libawt/awt/image/awt_ImageRep.c
41159 views
/*1* Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <string.h>2627#include "jni.h"28#include "jni_util.h"29#include "awt_parseImage.h"30#include "imageInitIDs.h"31#include "sun_awt_image_ImageRepresentation.h"3233static int compareLUTs(unsigned int *lut1, int numLut1, int transIdx,34unsigned int *lut2, int numLut2, unsigned char *cvtLut,35int *retNumLut1, int *retTransIdx, int *jniFlagP);3637static int findIdx(unsigned int rgb, unsigned int *lut, int numLut1);3839#define ALPHA_MASK 0xff00000040#ifndef FALSE41# define FALSE 042#endif43#ifndef TRUE44# define TRUE 145#endif4647#define CHECK_STRIDE(yy, hh, ss) \48if ((ss) != 0) { \49int limit = 0x7fffffff / ((ss) > 0 ? (ss) : -(ss)); \50if (limit < (yy) || limit < ((yy) + (hh) - 1)) { \51/* integer oveflow */ \52return JNI_FALSE; \53} \54} \5556#define CHECK_SRC() \57do { \58int pixeloffset; \59if (off < 0 || off >= srcDataLength) { \60return JNI_FALSE; \61} \62CHECK_STRIDE(0, h, scansize); \63\64/* check scansize */ \65pixeloffset = scansize * (h - 1); \66if ((w - 1) > (0x7fffffff - pixeloffset)) { \67return JNI_FALSE; \68} \69pixeloffset += (w - 1); \70\71if (off > (0x7fffffff - pixeloffset)) { \72return JNI_FALSE; \73} \74} while (0) \7576#define CHECK_DST(xx, yy) \77do { \78int soffset = (yy) * sStride; \79int poffset = (xx) * pixelStride; \80if (poffset > (0x7fffffff - soffset)) { \81return JNI_FALSE; \82} \83poffset += soffset; \84if (dstDataOff > (0x7fffffff - poffset)) { \85return JNI_FALSE; \86} \87poffset += dstDataOff; \88\89if (poffset < 0 || poffset >= dstDataLength) { \90return JNI_FALSE; \91} \92} while (0) \9394static jfieldID s_JnumSrcLUTID;95static jfieldID s_JsrcLUTtransIndexID;9697JNIEXPORT void JNICALL98Java_sun_awt_image_ImageRepresentation_initIDs(JNIEnv *env, jclass cls) {99CHECK_NULL(s_JnumSrcLUTID = (*env)->GetFieldID(env, cls, "numSrcLUT", "I"));100CHECK_NULL(s_JsrcLUTtransIndexID = (*env)->GetFieldID(env, cls,101"srcLUTtransIndex", "I"));102}103104/*105* This routine is used to draw ICM pixels into a default color model106*/107JNIEXPORT jboolean JNICALL108Java_sun_awt_image_ImageRepresentation_setICMpixels(JNIEnv *env, jclass cls,109jint x, jint y, jint w,110jint h, jintArray jlut,111jbyteArray jpix, jint off,112jint scansize,113jobject jict)114{115unsigned char *srcData = NULL;116jint srcDataLength;117int *dstData;118jint dstDataLength;119jint dstDataOff;120int *dstP, *dstyP;121unsigned char *srcyP, *srcP;122int *srcLUT = NULL;123int yIdx, xIdx;124int sStride;125int *cOffs;126int pixelStride;127jobject joffs = NULL;128jobject jdata = NULL;129130if (JNU_IsNull(env, jlut)) {131JNU_ThrowNullPointerException(env, "NullPointerException");132return JNI_FALSE;133}134135if (JNU_IsNull(env, jpix)) {136JNU_ThrowNullPointerException(env, "NullPointerException");137return JNI_FALSE;138}139140if (x < 0 || w < 1 || (0x7fffffff - x) < w) {141return JNI_FALSE;142}143144if (y < 0 || h < 1 || (0x7fffffff - y) < h) {145return JNI_FALSE;146}147148sStride = (*env)->GetIntField(env, jict, g_ICRscanstrID);149pixelStride = (*env)->GetIntField(env, jict, g_ICRpixstrID);150joffs = (*env)->GetObjectField(env, jict, g_ICRdataOffsetsID);151jdata = (*env)->GetObjectField(env, jict, g_ICRdataID);152153if (JNU_IsNull(env, jdata)) {154/* no destination buffer */155return JNI_FALSE;156}157158if (JNU_IsNull(env, joffs) || (*env)->GetArrayLength(env, joffs) < 1) {159/* invalid data offstes in raster */160return JNI_FALSE;161}162163srcDataLength = (*env)->GetArrayLength(env, jpix);164dstDataLength = (*env)->GetArrayLength(env, jdata);165166cOffs = (int *) (*env)->GetPrimitiveArrayCritical(env, joffs, NULL);167if (cOffs == NULL) {168(*env)->ExceptionClear(env);169JNU_ThrowNullPointerException(env, "Null channel offset array");170return JNI_FALSE;171}172173dstDataOff = cOffs[0];174175/* the offset array is not needed anymore and can be released */176(*env)->ReleasePrimitiveArrayCritical(env, joffs, cOffs, JNI_ABORT);177joffs = NULL;178cOffs = NULL;179180/* do basic validation: make sure that offsets for181* first pixel and for last pixel are safe to calculate and use */182CHECK_STRIDE(y, h, sStride);183CHECK_STRIDE(x, w, pixelStride);184185CHECK_DST(x, y);186CHECK_DST(x + w -1, y + h - 1);187188/* check source array */189CHECK_SRC();190191srcLUT = (int *) (*env)->GetPrimitiveArrayCritical(env, jlut, NULL);192if (srcLUT == NULL) {193(*env)->ExceptionClear(env);194JNU_ThrowNullPointerException(env, "Null IndexColorModel LUT");195return JNI_FALSE;196}197198srcData = (unsigned char *) (*env)->GetPrimitiveArrayCritical(env, jpix,199NULL);200if (srcData == NULL) {201(*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT);202(*env)->ExceptionClear(env);203JNU_ThrowNullPointerException(env, "Null data array");204return JNI_FALSE;205}206207dstData = (int *) (*env)->GetPrimitiveArrayCritical(env, jdata, NULL);208if (dstData == NULL) {209(*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT);210(*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT);211(*env)->ExceptionClear(env);212JNU_ThrowNullPointerException(env, "Null tile data array");213return JNI_FALSE;214}215216dstyP = dstData + dstDataOff + y*sStride + x*pixelStride;217srcyP = srcData + off;218for (yIdx = 0; yIdx < h; yIdx++, srcyP += scansize, dstyP+=sStride) {219srcP = srcyP;220dstP = dstyP;221for (xIdx = 0; xIdx < w; xIdx++, dstP+=pixelStride) {222*dstP = srcLUT[*srcP++];223}224}225226/* Release the locked arrays */227(*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, JNI_ABORT);228(*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT);229(*env)->ReleasePrimitiveArrayCritical(env, jdata, dstData, JNI_ABORT);230231return JNI_TRUE;232}233234JNIEXPORT jboolean JNICALL235Java_sun_awt_image_ImageRepresentation_setDiffICM(JNIEnv *env, jclass cls,236jint x, jint y, jint w,237jint h, jintArray jlut,238jint transIdx, jint numLut,239jobject jicm,240jbyteArray jpix, jint off,241jint scansize,242jobject jbct, jint dstDataOff)243{244unsigned int *srcLUT = NULL;245unsigned int *newLUT = NULL;246int sStride;247int pixelStride;248int mapSize;249jobject jdata = NULL;250jobject jnewlut = NULL;251jint srcDataLength;252jint dstDataLength;253unsigned char *srcData;254unsigned char *dstData;255unsigned char *dataP;256unsigned char *pixP;257int i;258int j;259int newNumLut;260int newTransIdx;261int jniFlag = JNI_ABORT;262unsigned char *ydataP;263unsigned char *ypixP;264unsigned char cvtLut[256];265266if (JNU_IsNull(env, jlut)) {267JNU_ThrowNullPointerException(env, "NullPointerException");268return JNI_FALSE;269}270271if (JNU_IsNull(env, jpix)) {272JNU_ThrowNullPointerException(env, "NullPointerException");273return JNI_FALSE;274}275276if (x < 0 || w < 1 || (0x7fffffff - x) < w) {277return JNI_FALSE;278}279280if (y < 0 || h < 1 || (0x7fffffff - y) < h) {281return JNI_FALSE;282}283284285sStride = (*env)->GetIntField(env, jbct, g_BCRscanstrID);286pixelStride =(*env)->GetIntField(env, jbct, g_BCRpixstrID);287jdata = (*env)->GetObjectField(env, jbct, g_BCRdataID);288jnewlut = (*env)->GetObjectField(env, jicm, g_ICMrgbID);289mapSize = (*env)->GetIntField(env, jicm, g_ICMmapSizeID);290291if (numLut < 0 || numLut > 256 || mapSize < 0 || mapSize > 256) {292/* Ether old or new ICM has a palette that exceeds capacity293of byte data type, so we have to convert the image data294to default representation.295*/296return JNI_FALSE;297}298299if (JNU_IsNull(env, jdata)) {300/* no destination buffer */301return JNI_FALSE;302}303304srcDataLength = (*env)->GetArrayLength(env, jpix);305dstDataLength = (*env)->GetArrayLength(env, jdata);306307CHECK_STRIDE(y, h, sStride);308CHECK_STRIDE(x, w, pixelStride);309310CHECK_DST(x, y);311CHECK_DST(x + w -1, y + h - 1);312313/* check source array */314CHECK_SRC();315316srcLUT = (unsigned int *) (*env)->GetPrimitiveArrayCritical(env, jlut,317NULL);318if (srcLUT == NULL) {319/* out of memory error already thrown */320return JNI_FALSE;321}322323newLUT = (unsigned int *) (*env)->GetPrimitiveArrayCritical(env, jnewlut,324NULL);325if (newLUT == NULL) {326(*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT,327JNI_ABORT);328/* out of memory error already thrown */329return JNI_FALSE;330}331332newNumLut = numLut;333newTransIdx = transIdx;334if (compareLUTs(srcLUT, numLut, transIdx, newLUT, mapSize,335cvtLut, &newNumLut, &newTransIdx, &jniFlag) == FALSE) {336/* Need to convert to ICR */337(*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT,338JNI_ABORT);339(*env)->ReleasePrimitiveArrayCritical(env, jnewlut, newLUT, JNI_ABORT);340return JNI_FALSE;341}342343/* Don't need these any more */344(*env)->ReleasePrimitiveArrayCritical(env, jlut, srcLUT, jniFlag);345(*env)->ReleasePrimitiveArrayCritical(env, jnewlut, newLUT, JNI_ABORT);346347if (newNumLut != numLut) {348/* Need to write back new number of entries in lut */349(*env)->SetIntField(env, cls, s_JnumSrcLUTID, newNumLut);350}351352if (newTransIdx != transIdx) {353(*env)->SetIntField(env, cls, s_JsrcLUTtransIndexID, newTransIdx);354}355356srcData = (unsigned char *) (*env)->GetPrimitiveArrayCritical(env, jpix,357NULL);358if (srcData == NULL) {359/* out of memory error already thrown */360return JNI_FALSE;361}362363dstData = (unsigned char *) (*env)->GetPrimitiveArrayCritical(env, jdata,364NULL);365if (dstData == NULL) {366(*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT);367/* out of memory error already thrown */368return JNI_FALSE;369}370371ydataP = dstData + dstDataOff + y*sStride + x*pixelStride;372ypixP = srcData + off;373374for (i=0; i < h; i++) {375dataP = ydataP;376pixP = ypixP;377for (j=0; j < w; j++) {378*dataP = cvtLut[*pixP];379dataP += pixelStride;380pixP++;381}382ydataP += sStride;383ypixP += scansize;384}385386(*env)->ReleasePrimitiveArrayCritical(env, jpix, srcData, JNI_ABORT);387(*env)->ReleasePrimitiveArrayCritical(env, jdata, dstData, JNI_ABORT);388389return JNI_TRUE;390}391392static int compareLUTs(unsigned int *lut1, int numLut1, int transIdx,393unsigned int *lut2, int numLut2, unsigned char *cvtLut,394int *retNumLut1, int *retTransIdx, int *jniFlagP)395{396int i;397int idx;398int newTransIdx = -1;399unsigned int rgb;400int changed = FALSE;401int maxSize = (numLut1 > numLut2 ? numLut1 : numLut2);402403*jniFlagP = JNI_ABORT;404405for (i=0; i < maxSize; i++) {406cvtLut[i] = i;407}408409for (i=0; i < numLut2; i++) {410/* If this slot in new palette is different from the411* same slot in current palette, then we try to find412* this color in other slots. On failure, add this color413* to current palette.414*/415if ((i >= numLut1) ||416(lut1[i] != lut2[i]))417{418rgb = lut2[i];419/* Transparent */420if ((rgb & ALPHA_MASK) == 0) {421if (transIdx == -1) {422if (numLut1 < 256) {423cvtLut[i] = numLut1;424newTransIdx = i;425transIdx = i;426numLut1++;427changed = TRUE;428}429else {430return FALSE;431}432}433cvtLut[i] = transIdx;434}435else {436if ((idx = findIdx(rgb, lut1, numLut1)) == -1) {437if (numLut1 < 256) {438lut1[numLut1] = rgb;439cvtLut[i] = numLut1;440numLut1++;441changed = TRUE;442}443else {444/* Bad news... need to convert image */445return FALSE;446}447} else {448cvtLut[i] = idx;449}450}451}452}453454if (changed) {455*jniFlagP = 0;456*retNumLut1 = numLut1;457if (newTransIdx != -1) {458*retTransIdx = newTransIdx;459}460}461return TRUE;462}463464static int findIdx(unsigned int rgb, unsigned int *lut, int numLut) {465int i;466467if ((rgb&0xff000000)==0) {468for (i=0; i < numLut; i++) {469if ((lut[i]&0xff000000)==0) return i;470}471}472else {473for (i=0; i < numLut; i++) {474if (lut[i] == rgb) return i;475}476}477return -1;478}479480481