Path: blob/master/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c
41159 views
/*1* Copyright (c) 2010, 2020, 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#ifdef HEADLESS26#error This file should not be included in headless library27#endif2829#include "X11SurfaceData.h"30#include <jni.h>31#include <math.h>32#include "Region.h"33#include "fontscalerdefs.h"3435#include <X11/extensions/Xrender.h>3637#ifdef __linux__38#include <sys/utsname.h>39#endif4041#ifndef X_RenderCreateLinearGradient42typedef struct _XLinearGradient {43XPointFixed p1;44XPointFixed p2;45} XLinearGradient;46#endif4748#ifndef X_RenderCreateRadialGradient49typedef struct _XCircle {50XFixed x;51XFixed y;52XFixed radius;53} XCircle;5455typedef struct _XRadialGradient {56XCircle inner;57XCircle outer;58} XRadialGradient;59#endif6061#include <dlfcn.h>6263#define BUILD_TRANSFORM_MATRIX(TRANSFORM, M00, M01, M02, M10, M11, M12) \64{ \65TRANSFORM.matrix[0][0] = M00; \66TRANSFORM.matrix[0][1] = M01; \67TRANSFORM.matrix[0][2] = M02; \68TRANSFORM.matrix[1][0] = M10; \69TRANSFORM.matrix[1][1] = M11; \70TRANSFORM.matrix[1][2] = M12; \71TRANSFORM.matrix[2][0] = 0; \72TRANSFORM.matrix[2][1] = 0; \73TRANSFORM.matrix[2][2] = 1<<16; \74}7576/* The xrender pipleine requires libXrender.so version 0.9.3 or later. */77#define REQUIRED_XRENDER_VER1 078#define REQUIRED_XRENDER_VER2 979#define REQUIRED_XRENDER_VER3 38081#define PKGINFO_LINE_LEN_MAX 25682#define PKGINFO_LINE_CNT_MAX 508384/*85* X protocol uses (u_int16)length to specify the length in 4 bytes quantities86* of the whole request. Both XRenderFillRectangles() and XFillRectangles()87* have provisions to fragment into several requests if the number of rectangles88* plus the current x request does not fit into 65535*4 bytes. While89* XRenderCreateLinearGradient() and XRenderCreateRadialGradient() have90* provisions to gracefully degrade if the resulting request would exceed91* 65535*4 bytes.92*93* Below, we define a cap of 65535*4 bytes for the maximum X request payload94* allowed for Non-(XRenderFillRectangles() or XFillRectangles()) API calls,95* just to be conservative. This is offset by the size of our maximum x*Req96* type in this compilation unit, which is xRenderCreateRadiaGradientReq.97*98* Note that sizeof(xRenderCreateRadiaGradientReq) = 3699*/100#define MAX_PAYLOAD (262140u - 36u)101#define MAXUINT (0xffffffffu)102103static jboolean IsXRenderAvailable(jboolean verbose, jboolean ignoreLinuxVersion) {104105void *xrenderlib;106107int major_opcode, first_event, first_error;108jboolean available = JNI_TRUE;109110if (!XQueryExtension(awt_display, "RENDER",111&major_opcode, &first_event, &first_error)) {112return JNI_FALSE;113}114115#if defined(_AIX)116// On AIX we have to use a special syntax because the shared libraries are packed in117// multi-architecture archives. We first try to load the system default libXrender118// which is contained in the 'X11.base.lib' fileset starting with AIX 6.1119xrenderlib = dlopen("libXrender.a(shr_64.o)", RTLD_GLOBAL | RTLD_LAZY | RTLD_MEMBER);120if (xrenderlib == NULL) {121// If the latter wasn't successful, we also try to load the version under /opt/freeware122// This may be downloaded from the "AIX Toolbox for Linux Applications" even for AIX 5.3123xrenderlib = dlopen("libXrender.a(libXrender.so.0)", RTLD_GLOBAL | RTLD_LAZY | RTLD_MEMBER);124}125if (xrenderlib != NULL) {126dlclose(xrenderlib);127} else {128available = JNI_FALSE;129}130#else131Dl_info info;132jboolean versionInfoIsFound = JNI_FALSE;133134memset(&info, 0, sizeof(Dl_info));135if (dladdr(&XRenderChangePicture, &info) && info.dli_fname != NULL) {136char pkgInfoPath[FILENAME_MAX];137char *pkgFileName = "/pkgconfig/xrender.pc";138size_t pkgFileNameLen = strlen(pkgFileName);139size_t pos, len = strlen(info.dli_fname);140141pos = len;142while (pos > 0 && info.dli_fname[pos] != '/') {143pos -= 1;144}145146if (pos > 0 && pos < (FILENAME_MAX - pkgFileNameLen - 1)) {147struct stat stat_info;148149// compose absolute filename to package config150strncpy(pkgInfoPath, info.dli_fname, pos);151152strcpy(pkgInfoPath + pos, pkgFileName);153pkgInfoPath[pos + pkgFileNameLen] = '\0';154155// check whether the config file exist and is a regular file156if ((stat(pkgInfoPath, &stat_info)== 0) &&157S_ISREG(stat_info.st_mode))158{159FILE *fp = fopen(pkgInfoPath, "r");160if (fp != NULL) {161char line[PKGINFO_LINE_LEN_MAX];162int lineCount = PKGINFO_LINE_CNT_MAX;163char *versionPrefix = "Version: ";164size_t versionPrefixLen = strlen(versionPrefix);165166// look for version167while(fgets(line,sizeof(line),fp) != NULL && --lineCount > 0) {168size_t lineLen = strlen(line);169170if (lineLen > versionPrefixLen &&171strncmp(versionPrefix, line, versionPrefixLen) == 0)172{173int v1 = 0, v2 = 0, v3 = 0;174int numNeeded = 3,numProcessed;175char* version = line + versionPrefixLen;176numProcessed = sscanf(version, "%d.%d.%d", &v1, &v2, &v3);177178if (numProcessed == numNeeded) {179// we successfuly read the library version180versionInfoIsFound = JNI_TRUE;181182if (REQUIRED_XRENDER_VER1 == v1 &&183((REQUIRED_XRENDER_VER2 > v2) ||184((REQUIRED_XRENDER_VER2 == v2) && (REQUIRED_XRENDER_VER3 > v3))))185{186available = JNI_FALSE;187188if (verbose) {189printf("INFO: the version %d.%d.%d of libXrender.so is "190"not supported.\n\tSee release notes for more details.\n",191v1, v2, v3);192fflush(stdout);193}194} else {195if (verbose) {196printf("INFO: The version of libXrender.so "197"is detected as %d.%d%d\n", v1, v2, v3);198fflush(stdout);199}200}201}202break;203}204}205fclose(fp);206}207}208}209}210if (verbose && !versionInfoIsFound) {211printf("WARNING: The version of libXrender.so cannot be detected.\n,"212"The pipe line will be enabled, but note that versions less than 0.9.3\n"213"may cause hangs and crashes\n"214"\tSee the release notes for more details.\n");215fflush(stdout);216}217#endif218219#ifdef __linux__220/*221* Check for Linux >= 3.5 (Ubuntu 12.04.02 LTS) to avoid hitting222* https://bugs.freedesktop.org/show_bug.cgi?id=48045223*/224struct utsname utsbuf;225if(uname(&utsbuf) >= 0) {226int major, minor, revision;227if(sscanf(utsbuf.release, "%i.%i.%i", &major, &minor, &revision) == 3) {228if(major < 3 || (major == 3 && minor < 5)) {229if(!ignoreLinuxVersion) {230available = JNI_FALSE;231}232else if(verbose) {233printf("WARNING: Linux < 3.5 detected.\n"234"The pipeline will be enabled, but graphical "235"artifacts can occur with old graphic drivers.\n"236"See the release notes for more details.\n");237fflush(stdout);238}239}240}241}242#endif // __linux__243244return available;245}246/*247* Class: sun_awt_X11GraphicsEnvironment248* Method: initGLX249* Signature: ()Z250*/251JNIEXPORT jboolean JNICALL252Java_sun_awt_X11GraphicsEnvironment_initXRender253(JNIEnv *env, jclass x11ge, jboolean verbose, jboolean ignoreLinuxVersion)254{255static jboolean xrenderAvailable = JNI_FALSE;256static jboolean firstTime = JNI_TRUE;257258if (firstTime) {259#ifdef DISABLE_XRENDER_BY_DEFAULT260if (verbose == JNI_FALSE) {261xrenderAvailable = JNI_FALSE;262firstTime = JNI_FALSE;263return xrenderAvailable;264}265#endif266AWT_LOCK();267xrenderAvailable = IsXRenderAvailable(verbose, ignoreLinuxVersion);268AWT_UNLOCK();269firstTime = JNI_FALSE;270}271return xrenderAvailable;272}273274275JNIEXPORT void JNICALL276Java_sun_java2d_xr_XRBackendNative_initIDs(JNIEnv *env, jclass cls) {277char *maskData;278XImage* defaultImg;279jfieldID maskImgID;280jlong fmt8;281jlong fmt32;282283jfieldID a8ID = (*env)->GetStaticFieldID(env, cls, "FMTPTR_A8", "J");284if (a8ID == NULL) {285return;286}287jfieldID argb32ID = (*env)->GetStaticFieldID(env, cls, "FMTPTR_ARGB32", "J");288if (argb32ID == NULL) {289return;290}291292if (awt_display == (Display *)NULL) {293return;294}295296fmt8 = ptr_to_jlong(XRenderFindStandardFormat(awt_display, PictStandardA8));297fmt32 = ptr_to_jlong(XRenderFindStandardFormat(awt_display, PictStandardARGB32));298299(*env)->SetStaticLongField(env, cls, a8ID, fmt8);300(*env)->SetStaticLongField(env, cls, argb32ID, fmt32);301302maskData = (char *) malloc(32*32);303if (maskData == NULL) {304return;305}306307defaultImg = XCreateImage(awt_display, NULL, 8, ZPixmap, 0, maskData, 32, 32, 8, 0);308defaultImg->data = maskData; //required?309maskImgID = (*env)->GetStaticFieldID(env, cls, "MASK_XIMG", "J");310if (maskImgID == NULL) {311return;312}313314(*env)->SetStaticLongField(env, cls, maskImgID, ptr_to_jlong(defaultImg));315}316317JNIEXPORT void JNICALL318Java_sun_java2d_xr_XRBackendNative_freeGC319(JNIEnv *env, jobject this, jlong gc) {320XFreeGC(awt_display, (GC) jlong_to_ptr(gc));321}322323JNIEXPORT jlong JNICALL324Java_sun_java2d_xr_XRBackendNative_createGC325(JNIEnv *env, jobject this, jint drawable) {326GC xgc = XCreateGC(awt_display, (Drawable) drawable, 0L, NULL);327return ptr_to_jlong(xgc);328}329330JNIEXPORT jint JNICALL331Java_sun_java2d_xr_XRBackendNative_createPixmap(JNIEnv *env, jobject this,332jint drawable, jint depth,333jint width, jint height) {334return (jint) XCreatePixmap(awt_display, (Drawable) drawable,335width, height, depth);336}337338JNIEXPORT jint JNICALL339Java_sun_java2d_xr_XRBackendNative_createPictureNative340(JNIEnv *env, jclass cls, jint drawable, jlong formatPtr) {341XRenderPictureAttributes pict_attr;342return XRenderCreatePicture(awt_display, (Drawable) drawable,343(XRenderPictFormat *) jlong_to_ptr(formatPtr),3440, &pict_attr);345}346347JNIEXPORT void JNICALL348Java_sun_java2d_xr_XRBackendNative_freePicture349(JNIEnv *env, jobject this, jint picture) {350XRenderFreePicture(awt_display, (Picture) picture);351}352353JNIEXPORT void JNICALL354Java_sun_java2d_xr_XRBackendNative_freePixmap355(JNIEnv *env, jobject this, jint pixmap) {356XFreePixmap(awt_display, (Pixmap) pixmap);357}358359JNIEXPORT void JNICALL360Java_sun_java2d_xr_XRBackendNative_setPictureRepeat361(JNIEnv *env, jobject this, jint picture, jint repeat) {362XRenderPictureAttributes pict_attr;363pict_attr.repeat = repeat;364XRenderChangePicture (awt_display, (Picture) picture, CPRepeat, &pict_attr);365}366367368JNIEXPORT void JNICALL369Java_sun_java2d_xr_XRBackendNative_setGCExposures370(JNIEnv *env, jobject this, jlong gc, jboolean exposure) {371XSetGraphicsExposures(awt_display,372(GC) jlong_to_ptr(gc), exposure ? True : False); //TODO: ????373}374375JNIEXPORT void JNICALL376Java_sun_java2d_xr_XRBackendNative_setGCForeground377(JNIEnv *env, jobject this, jlong gc, jint pixel) {378XSetForeground(awt_display, (GC) jlong_to_ptr(gc), (unsigned long) pixel);379}380381382JNIEXPORT void JNICALL383Java_sun_java2d_xr_XRBackendNative_copyArea384(JNIEnv *env, jobject this, jint src, jint dst, jlong gc,385jint srcx, jint srcy, jint width, jint height, jint dstx, jint dsty) {386XCopyArea(awt_display, (Drawable) src, (Drawable) dst,387(GC) jlong_to_ptr(gc), srcx, srcy, width, height, dstx, dsty);388}389390JNIEXPORT void JNICALL391Java_sun_java2d_xr_XRBackendNative_renderComposite392(JNIEnv *env, jobject this, jbyte op, jint src, jint mask, jint dst,393jint srcX, jint srcY, jint maskX, jint maskY,394jint dstX, jint dstY, jint width, jint height) {395XRenderComposite (awt_display, op,396(Picture)src, (Picture)mask, (Picture)dst,397srcX, srcY, maskX, maskY, dstX, dstY, width, height);398}399400JNIEXPORT void JNICALL401Java_sun_java2d_xr_XRBackendNative_renderRectangle402(JNIEnv *env, jobject this, jint dst, jbyte op,403jshort red, jshort green, jshort blue, jshort alpha,404jint x, jint y, jint width, jint height) {405XRenderColor color;406color.alpha = alpha;407color.red = red;408color.green = green;409color.blue = blue;410XRenderFillRectangle(awt_display, op, (Picture) dst, &color,411x, y, width, height);412}413414JNIEXPORT void JNICALL415Java_sun_java2d_xr_XRBackendNative_XRenderRectanglesNative416(JNIEnv *env, jclass xsd, jint dst, jbyte op,417jshort red, jshort green, jshort blue, jshort alpha,418jintArray rectArray, jint rectCnt) {419int i;420jint* rects;421XRectangle *xRects;422XRectangle sRects[256];423424XRenderColor color;425color.alpha = alpha;426color.red = red;427color.green = green;428color.blue = blue;429430if (rectCnt <= 256) {431xRects = &sRects[0];432} else {433if (MAXUINT / sizeof(XRectangle) < (unsigned)rectCnt) {434/* rectCnt too big, integer overflow */435return;436}437xRects = (XRectangle *) malloc(sizeof(XRectangle) * rectCnt);438if (xRects == NULL) {439return;440}441}442443if ((rects = (jint *)444(*env)->GetPrimitiveArrayCritical(env, rectArray, NULL)) == NULL) {445if (xRects != &sRects[0]) {446free(xRects);447}448return;449}450451for (i=0; i < rectCnt; i++) {452xRects[i].x = rects[i*4 + 0];453xRects[i].y = rects[i*4 + 1];454xRects[i].width = rects[i*4 + 2];455xRects[i].height = rects[i*4 + 3];456}457458XRenderFillRectangles(awt_display, op,459(Picture) dst, &color, xRects, rectCnt);460461(*env)->ReleasePrimitiveArrayCritical(env, rectArray, rects, JNI_ABORT);462if (xRects != &sRects[0]) {463free(xRects);464}465}466467JNIEXPORT void JNICALL468Java_sun_java2d_xr_XRBackendNative_XRSetTransformNative469(JNIEnv *env, jclass xsd, jint pic,470jint m00, jint m01, jint m02, jint m10, jint m11, jint m12) {471472XTransform tr;473BUILD_TRANSFORM_MATRIX(tr, m00, m01, m02, m10, m11, m12);474XRenderSetPictureTransform (awt_display, (Picture) pic, &tr);475}476477JNIEXPORT jint JNICALL478Java_sun_java2d_xr_XRBackendNative_XRCreateLinearGradientPaintNative479(JNIEnv *env, jclass xsd, jfloatArray fractionsArray,480jshortArray pixelsArray, jint x1, jint y1, jint x2, jint y2,481jint numStops, jint repeat) {482jint i;483jshort* pixels;484jfloat* fractions;485XRenderPictureAttributes pict_attr;486Picture gradient = 0;487XRenderColor *colors;488XFixed *stops;489XLinearGradient grad;490491if (MAX_PAYLOAD / (sizeof(XRenderColor) + sizeof(XFixed))492< (unsigned)numStops) {493/* numStops too big, payload overflow */494return -1;495}496497if ((pixels = (jshort *)498(*env)->GetPrimitiveArrayCritical(env, pixelsArray, NULL)) == NULL) {499return -1;500}501if ((fractions = (jfloat *)502(*env)->GetPrimitiveArrayCritical(env, fractionsArray, NULL)) == NULL) {503(*env)->ReleasePrimitiveArrayCritical(env,504pixelsArray, pixels, JNI_ABORT);505return -1;506}507508grad.p1.x = x1;509grad.p1.y = y1;510grad.p2.x = x2;511grad.p2.y = y2;512513/*TODO optimized & malloc check*/514colors = (XRenderColor *) malloc(numStops * sizeof(XRenderColor));515stops = (XFixed *) malloc(numStops * sizeof(XFixed));516517if (colors == NULL || stops == NULL) {518if (colors != NULL) {519free(colors);520}521if (stops != NULL) {522free(stops);523}524(*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT);525(*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT);526return -1;527}528529for (i=0; i < numStops; i++) {530stops[i] = XDoubleToFixed(fractions[i]);531colors[i].alpha = pixels[i*4 + 0];532colors[i].red = pixels[i*4 + 1];533colors[i].green = pixels[i*4 + 2];534colors[i].blue = pixels[i*4 + 3];535}536gradient = XRenderCreateLinearGradient(awt_display, &grad, stops, colors, numStops);537free(colors);538free(stops);539540(*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT);541(*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT);542543if (gradient != 0) {544pict_attr.repeat = repeat;545XRenderChangePicture (awt_display, gradient, CPRepeat, &pict_attr);546}547548return (jint) gradient;549}550551552JNIEXPORT jint JNICALL553Java_sun_java2d_xr_XRBackendNative_XRCreateRadialGradientPaintNative554(JNIEnv *env, jclass xsd, jfloatArray fractionsArray,555jshortArray pixelsArray, jint numStops,556jint centerX, jint centerY,557jint innerRadius, jint outerRadius, jint repeat) {558jint i;559jshort* pixels;560jfloat* fractions;561XRenderPictureAttributes pict_attr;562Picture gradient = 0;563XRenderColor *colors;564XFixed *stops;565XRadialGradient grad;566567if (MAX_PAYLOAD / (sizeof(XRenderColor) + sizeof(XFixed))568< (unsigned)numStops) {569/* numStops too big, payload overflow */570return -1;571}572573if ((pixels =574(jshort *)(*env)->GetPrimitiveArrayCritical(env, pixelsArray, NULL)) == NULL) {575return -1;576}577if ((fractions = (jfloat *)578(*env)->GetPrimitiveArrayCritical(env, fractionsArray, NULL)) == NULL) {579(*env)->ReleasePrimitiveArrayCritical(env,580pixelsArray, pixels, JNI_ABORT);581return -1; //TODO release pixels first582}583584grad.inner.x = centerX;585grad.inner.y = centerY;586grad.inner.radius = innerRadius;587grad.outer.x = centerX;588grad.outer.y = centerY;589grad.outer.radius = outerRadius;590591/*TODO optimized & malloc check*/592colors = (XRenderColor *) malloc(numStops * sizeof(XRenderColor));593stops = (XFixed *) malloc(numStops * sizeof(XFixed));594595if (colors == NULL || stops == NULL) {596if (colors != NULL) {597free(colors);598}599if (stops != NULL) {600free(stops);601}602(*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT);603(*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT);604return -1;605}606607for (i=0; i < numStops; i++) {608stops[i] = XDoubleToFixed(fractions[i]);609colors[i].alpha = pixels[i*4 + 0];610colors[i].red = pixels[i*4 + 1];611colors[i].green = pixels[i*4 + 2];612colors[i].blue = pixels[i*4 + 3];613}614gradient = (jint) XRenderCreateRadialGradient(awt_display, &grad, stops, colors, numStops);615free(colors);616free(stops);617618(*env)->ReleasePrimitiveArrayCritical(env, pixelsArray, pixels, JNI_ABORT);619(*env)->ReleasePrimitiveArrayCritical(env, fractionsArray, fractions, JNI_ABORT);620621622if (gradient != 0) {623pict_attr.repeat = repeat;624XRenderChangePicture (awt_display, gradient, CPRepeat, &pict_attr);625}626627return (jint) gradient;628}629630JNIEXPORT void JNICALL631Java_sun_java2d_xr_XRBackendNative_setFilter632(JNIEnv *env, jobject this, jint picture, jint filter) {633634char * filterName = "fast";635636switch(filter) {637case 0:638filterName = "fast";639break;640641case 1:642filterName = "good";643break;644645case 2:646filterName = "best";647break;648}649650XRenderSetPictureFilter(awt_display, (Picture) picture, filterName, NULL, 0);651}652653JNIEXPORT void JNICALL654Java_sun_java2d_xr_XRBackendNative_XRSetClipNative655(JNIEnv *env, jclass xsd, jlong dst,656jint x1, jint y1, jint x2, jint y2,657jobject complexclip, jboolean isGC)658{659int numrects;660XRectangle rects[256];661XRectangle *pRect = rects;662663numrects = RegionToYXBandedRectangles(env,664x1, y1, x2, y2, complexclip,665&pRect, 256);666667if (isGC == JNI_TRUE) {668if (dst != (jlong) 0) {669XSetClipRectangles(awt_display, (GC) jlong_to_ptr(dst), 0, 0, pRect, numrects, YXBanded);670}671} else {672XRenderSetPictureClipRectangles (awt_display, (Picture) dst, 0, 0, pRect, numrects);673}674675if (pRect != rects) {676free(pRect);677}678}679680JNIEXPORT void JNICALL681Java_sun_java2d_xr_XRBackendNative_putMaskNative682(JNIEnv *env, jclass cls, jint drawable, jlong gc, jbyteArray imageData,683jint sx, jint sy, jint dx, jint dy, jint width, jint height,684jint maskOff, jint maskScan, jfloat ea, jlong imgPtr) {685686int line, pix;687char *mask;688char *defaultData;689XImage *defaultImg, *img;690jboolean imageFits;691692if ((mask = (char *)693(*env)->GetPrimitiveArrayCritical(env, imageData, NULL)) == NULL) {694return;695}696697defaultImg = (XImage *) jlong_to_ptr(imgPtr);698699if (ea != 1.0f) {700for (line=0; line < height; line++) {701for (pix=0; pix < width; pix++) {702size_t index = (size_t) maskScan * line + pix + maskOff;703mask[index] = (((unsigned char) mask[index])*ea);704}705}706}707708/*709* 1. If existing XImage and supplied buffer match, only adjust the data pointer710* 2. If existing XImage is large enough to hold the data but does not match in711* scan the data is copied to fit the XImage.712* 3. If data is larger than the existing XImage a new temporary XImage is713* allocated.714* The default XImage is optimized for the AA tiles, which are currently 32x32.715*/716defaultData = defaultImg->data;717img = defaultImg;718imageFits = defaultImg->width >= width && defaultImg->height >= height;719720if (imageFits &&721maskOff == defaultImg->xoffset && maskScan == defaultImg->bytes_per_line) {722defaultImg->data = mask;723} else {724if (imageFits) {725for (line=0; line < height; line++) {726for (pix=0; pix < width; pix++) {727img->data[(size_t) line * img->bytes_per_line + pix] =728(unsigned char) (mask[(size_t) maskScan * line + pix + maskOff]);729}730}731} else {732img = XCreateImage(awt_display, NULL, 8, ZPixmap,733maskOff, mask, maskScan, height, 8, 0);734}735}736737XPutImage(awt_display, (Pixmap) drawable, (GC) jlong_to_ptr(gc),738img, 0, 0, 0, 0, width, height);739(*env)->ReleasePrimitiveArrayCritical(env, imageData, mask, JNI_ABORT);740741if (img != defaultImg) {742img->data = NULL;743XDestroyImage(img);744}745defaultImg->data = defaultData;746}747748JNIEXPORT void JNICALL749Java_sun_java2d_xr_XRBackendNative_XRAddGlyphsNative750(JNIEnv *env, jclass cls, jint glyphSet,751jlongArray glyphInfoPtrsArray, jint glyphCnt,752jbyteArray pixelDataArray, int pixelDataLength) {753jlong *glyphInfoPtrs;754unsigned char *pixelData;755int i;756757if (MAX_PAYLOAD / (sizeof(XGlyphInfo) + sizeof(Glyph))758< (unsigned)glyphCnt) {759/* glyphCnt too big, payload overflow */760return;761}762763XGlyphInfo *xginfo = (XGlyphInfo *) malloc(sizeof(XGlyphInfo) * glyphCnt);764Glyph *gid = (Glyph *) malloc(sizeof(Glyph) * glyphCnt);765766if (xginfo == NULL || gid == NULL) {767if (xginfo != NULL) {768free(xginfo);769}770if (gid != NULL) {771free(gid);772}773return;774}775776if ((glyphInfoPtrs = (jlong *)(*env)->777GetPrimitiveArrayCritical(env, glyphInfoPtrsArray, NULL)) == NULL)778{779free(xginfo);780free(gid);781return;782}783784if ((pixelData = (unsigned char *)785(*env)->GetPrimitiveArrayCritical(env, pixelDataArray, NULL)) == NULL)786{787(*env)->ReleasePrimitiveArrayCritical(env,788glyphInfoPtrsArray, glyphInfoPtrs, JNI_ABORT);789free(xginfo);790free(gid);791return;792}793794for (i=0; i < glyphCnt; i++) {795GlyphInfo *jginfo = (GlyphInfo *) jlong_to_ptr(glyphInfoPtrs[i]);796797// 'jginfo->cellInfo' is of type 'void*'798// (see definition of 'GlyphInfo' in fontscalerdefs.h)799// 'Glyph' is typedefed to 'unsigned long'800// (see http://www.x.org/releases/X11R7.7/doc/libXrender/libXrender.txt)801// Maybe we should assert that (sizeof(void*) == sizeof(Glyph)) ?802gid[i] = (Glyph) (jginfo->cellInfo);803xginfo[i].x = (-jginfo->topLeftX);804xginfo[i].y = (-jginfo->topLeftY);805xginfo[i].width = jginfo->width;806xginfo[i].height = jginfo->height;807xginfo[i].xOff = round(jginfo->advanceX);808xginfo[i].yOff = round(jginfo->advanceY);809}810811XRenderAddGlyphs(awt_display, glyphSet, &gid[0], &xginfo[0], glyphCnt,812(const char*)pixelData, pixelDataLength);813814(*env)->ReleasePrimitiveArrayCritical(env, glyphInfoPtrsArray, glyphInfoPtrs, JNI_ABORT);815(*env)->ReleasePrimitiveArrayCritical(env, pixelDataArray, pixelData, JNI_ABORT);816817free(xginfo);818free(gid);819}820821JNIEXPORT void JNICALL822Java_sun_java2d_xr_XRBackendNative_XRFreeGlyphsNative823(JNIEnv *env, jclass cls, jint glyphSet, jintArray gidArray, jint glyphCnt) {824825if (MAX_PAYLOAD / sizeof(Glyph) < (unsigned)glyphCnt) {826/* glyphCnt too big, payload overflow */827return;828}829830/* The glyph ids are 32 bit but may be stored in a 64 bit long on831* a 64 bit architecture. So optimise the 32 bit case to avoid832* extra stack or heap allocations by directly referencing the833* underlying Java array and only allocate on 64 bit.834*/835if (sizeof(jint) == sizeof(Glyph)) {836jint *gids =837(*env)->GetPrimitiveArrayCritical(env, gidArray, NULL);838if (gids == NULL) {839return;840} else {841XRenderFreeGlyphs(awt_display,842(GlyphSet)glyphSet, (Glyph *)gids, glyphCnt);843(*env)->ReleasePrimitiveArrayCritical(env, gidArray,844gids, JNI_ABORT);845}846return;847} else {848Glyph stack_ids[64];849Glyph *gids = NULL;850jint* jgids = NULL;851int i;852853if (glyphCnt <= 64) {854gids = stack_ids;855} else {856gids = (Glyph *)malloc(sizeof(Glyph) * glyphCnt);857if (gids == NULL) {858return;859}860}861jgids = (*env)->GetPrimitiveArrayCritical(env, gidArray, NULL);862if (jgids == NULL) {863if (gids != stack_ids) {864free(gids);865}866return;867}868for (i=0; i < glyphCnt; i++) {869gids[i] = jgids[i];870}871XRenderFreeGlyphs(awt_display,872(GlyphSet) glyphSet, gids, glyphCnt);873(*env)->ReleasePrimitiveArrayCritical(env, gidArray,874jgids, JNI_ABORT);875if (gids != stack_ids) {876free(gids);877}878}879}880881JNIEXPORT jint JNICALL882Java_sun_java2d_xr_XRBackendNative_XRenderCreateGlyphSetNative883(JNIEnv *env, jclass cls, jlong format) {884return XRenderCreateGlyphSet(awt_display, (XRenderPictFormat *) jlong_to_ptr(format));885}886887JNIEXPORT void JNICALL888Java_sun_java2d_xr_XRBackendNative_XRenderCompositeTextNative889(JNIEnv *env, jclass cls, jint op, jint src, jint dst,890jint sx, jint sy, jlong maskFmt, jintArray eltArray,891jintArray glyphIDArray, jint eltCnt, jint glyphCnt) {892jint i;893jint *ids;894jint *elts;895XGlyphElt32 *xelts;896unsigned int *xids;897XGlyphElt32 selts[24];898unsigned int sids[256];899int charCnt = 0;900901if ((MAX_PAYLOAD / sizeof(XGlyphElt32) < (unsigned)eltCnt)902|| (MAX_PAYLOAD / sizeof(unsigned int) < (unsigned)glyphCnt)903|| ((MAX_PAYLOAD - sizeof(XGlyphElt32)*(unsigned)eltCnt) /904sizeof(unsigned int) < (unsigned)glyphCnt))905{906/* (eltCnt, glyphCnt) too big, payload overflow */907return;908}909910if (eltCnt <= 24) {911xelts = &selts[0];912}else {913xelts = (XGlyphElt32 *) malloc(sizeof(XGlyphElt32) * eltCnt);914if (xelts == NULL) {915return;916}917}918919if (glyphCnt <= 256) {920xids = &sids[0];921} else {922xids = (unsigned int*)malloc(sizeof(unsigned int) * glyphCnt);923if (xids == NULL) {924if (xelts != &selts[0]) {925free(xelts);926}927return;928}929}930931if ((ids = (jint *)932(*env)->GetPrimitiveArrayCritical(env, glyphIDArray, NULL)) == NULL) {933if (xelts != &selts[0]) {934free(xelts);935}936if (xids != &sids[0]) {937free(xids);938}939return;940}941if ((elts = (jint *)942(*env)->GetPrimitiveArrayCritical(env, eltArray, NULL)) == NULL) {943(*env)->ReleasePrimitiveArrayCritical(env,944glyphIDArray, ids, JNI_ABORT);945if (xelts != &selts[0]) {946free(xelts);947}948if (xids != &sids[0]) {949free(xids);950}951return;952}953954for (i=0; i < glyphCnt; i++) {955xids[i] = ids[i];956}957958for (i=0; i < eltCnt; i++) {959xelts[i].nchars = elts[i*4 + 0];960xelts[i].xOff = elts[i*4 + 1];961xelts[i].yOff = elts[i*4 + 2];962xelts[i].glyphset = (GlyphSet) elts[i*4 + 3];963xelts[i].chars = &xids[charCnt];964965charCnt += xelts[i].nchars;966}967968XRenderCompositeText32(awt_display, op, (Picture) src, (Picture) dst,969(XRenderPictFormat *) jlong_to_ptr(maskFmt),970sx, sy, 0, 0, xelts, eltCnt);971972(*env)->ReleasePrimitiveArrayCritical(env, glyphIDArray, ids, JNI_ABORT);973(*env)->ReleasePrimitiveArrayCritical(env, eltArray, elts, JNI_ABORT);974975if (xelts != &selts[0]) {976free(xelts);977}978979if (xids != &sids[0]) {980free(xids);981}982}983984JNIEXPORT void JNICALL985Java_sun_java2d_xr_XRBackendNative_setGCMode986(JNIEnv *env, jobject this, jlong gc, jboolean copy) {987GC xgc = (GC) jlong_to_ptr(gc);988989if (copy == JNI_TRUE) {990XSetFunction(awt_display, xgc, GXcopy);991} else {992XSetFunction(awt_display, xgc, GXxor);993}994}995996JNIEXPORT void JNICALL997Java_sun_java2d_xr_XRBackendNative_GCRectanglesNative998(JNIEnv *env, jclass xsd, jint dst, jlong gc,999jintArray rectArray, jint rectCnt) {1000int i;1001jint* rects;1002XRectangle *xRects;1003XRectangle sRects[256];10041005if (rectCnt <= 256) {1006xRects = &sRects[0];1007} else {1008if (MAXUINT / sizeof(XRectangle) < (unsigned)rectCnt) {1009/* rectCnt too big, integer overflow */1010return;1011}10121013xRects = (XRectangle *) malloc(sizeof(XRectangle) * rectCnt);1014if (xRects == NULL) {1015return;1016}1017}10181019if ((rects = (jint*)1020(*env)->GetPrimitiveArrayCritical(env, rectArray, NULL)) == NULL) {1021if (xRects != &sRects[0]) {1022free(xRects);1023}1024return;1025}10261027for (i=0; i < rectCnt; i++) {1028xRects[i].x = rects[i*4 + 0];1029xRects[i].y = rects[i*4 + 1];1030xRects[i].width = rects[i*4 + 2];1031xRects[i].height = rects[i*4 + 3];1032}10331034XFillRectangles(awt_display, (Drawable) dst, (GC) jlong_to_ptr(gc), xRects, rectCnt);10351036(*env)->ReleasePrimitiveArrayCritical(env, rectArray, rects, JNI_ABORT);1037if (xRects != &sRects[0]) {1038free(xRects);1039}1040}104110421043