/*
* Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <stdlib.h>
#include <jni.h>
#include <jlong.h>
#include "X11SurfaceData.h"
#include "Region.h"
JNIEXPORT void JNICALL
Java_sun_java2d_x11_X11PMBlitLoops_nativeBlit
(JNIEnv *env, jobject joSelf,
jlong srcData, jlong dstData,
jlong gc, jobject clip,
jint srcx, jint srcy,
jint dstx, jint dsty,
jint width, jint height)
{
#ifndef HEADLESS
X11SDOps *srcXsdo, *dstXsdo;
SurfaceDataBounds span, srcBounds;
RegionData clipInfo;
GC xgc;
if (width <= 0 || height <= 0) {
return;
}
srcXsdo = (X11SDOps *)jlong_to_ptr(srcData);
if (srcXsdo == NULL) {
return;
}
dstXsdo = (X11SDOps *)jlong_to_ptr(dstData);
if (dstXsdo == NULL) {
return;
}
if (Region_GetInfo(env, clip, &clipInfo)) {
return;
}
xgc = (GC)gc;
if (xgc == NULL) {
return;
}
#ifdef MITSHM
if (srcXsdo->isPixmap) {
X11SD_UnPuntPixmap(srcXsdo);
}
#endif /* MITSHM */
/* clip the source rect to the source pixmap's dimensions */
srcBounds.x1 = srcx;
srcBounds.y1 = srcy;
srcBounds.x2 = srcx + width;
srcBounds.y2 = srcy + height;
SurfaceData_IntersectBoundsXYXY(&srcBounds,
0, 0, srcXsdo->pmWidth, srcXsdo->pmHeight);
span.x1 = dstx;
span.y1 = dsty;
span.x2 = dstx + width;
span.y2 = dsty + height;
/* intersect the source and dest rects */
SurfaceData_IntersectBlitBounds(&srcBounds, &span,
dstx - srcx, dsty - srcy);
srcx = srcBounds.x1;
srcy = srcBounds.y1;
dstx = span.x1;
dsty = span.y1;
if (srcXsdo->bitmask != 0) {
XSetClipOrigin(awt_display, xgc, dstx - srcx, dsty - srcy);
XSetClipMask(awt_display, xgc, srcXsdo->bitmask);
}
Region_IntersectBounds(&clipInfo, &span);
if (!Region_IsEmpty(&clipInfo)) {
Region_StartIteration(env, &clipInfo);
srcx -= dstx;
srcy -= dsty;
while (Region_NextIteration(&clipInfo, &span)) {
XCopyArea(awt_display, srcXsdo->drawable, dstXsdo->drawable, xgc,
srcx + span.x1, srcy + span.y1,
span.x2 - span.x1, span.y2 - span.y1,
span.x1, span.y1);
}
Region_EndIteration(env, &clipInfo);
}
if (srcXsdo->bitmask != 0) {
XSetClipMask(awt_display, xgc, None);
}
#ifdef MITSHM
if (srcXsdo->shmPMData.usingShmPixmap) {
srcXsdo->shmPMData.xRequestSent = JNI_TRUE;
}
#endif /* MITSHM */
X11SD_DirectRenderNotify(env, dstXsdo);
#endif /* !HEADLESS */
}
JNIEXPORT void JNICALL
Java_sun_java2d_x11_X11PMBlitBgLoops_nativeBlitBg
(JNIEnv *env, jobject joSelf,
jlong srcData, jlong dstData,
jlong xgc, jint pixel,
jint srcx, jint srcy,
jint dstx, jint dsty,
jint width, jint height)
{
#ifndef HEADLESS
X11SDOps *srcXsdo, *dstXsdo;
GC dstGC;
SurfaceDataBounds dstBounds, srcBounds;
Drawable srcDrawable;
if (width <= 0 || height <= 0) {
return;
}
srcXsdo = (X11SDOps *)jlong_to_ptr(srcData);
if (srcXsdo == NULL) {
return;
}
dstXsdo = (X11SDOps *)jlong_to_ptr(dstData);
if (dstXsdo == NULL) {
return;
}
dstGC = (GC)xgc;
if (dstGC == NULL) {
return;
}
#ifdef MITSHM
if (srcXsdo->isPixmap) {
X11SD_UnPuntPixmap(srcXsdo);
}
#endif /* MITSHM */
srcDrawable = srcXsdo->GetPixmapWithBg(env, srcXsdo, pixel);
if (srcDrawable == 0) {
return;
}
/* clip the source rect to the source pixmap's dimensions */
srcBounds.x1 = srcx;
srcBounds.y1 = srcy;
srcBounds.x2 = srcx + width;
srcBounds.y2 = srcy + height;
SurfaceData_IntersectBoundsXYXY(&srcBounds,
0, 0, srcXsdo->pmWidth, srcXsdo->pmHeight);
dstBounds.x1 = dstx;
dstBounds.y1 = dsty;
dstBounds.x2 = dstx + width;
dstBounds.y2 = dsty + height;
/* intersect the source and dest rects */
SurfaceData_IntersectBlitBounds(&srcBounds, &dstBounds,
dstx - srcx, dsty - srcy);
srcx = srcBounds.x1;
srcy = srcBounds.y1;
dstx = dstBounds.x1;
dsty = dstBounds.y1;
width = srcBounds.x2 - srcBounds.x1;
height = srcBounds.y2 - srcBounds.y1;
/* do an unmasked copy as we've already filled transparent
pixels of the source image with the desired color */
XCopyArea(awt_display, srcDrawable, dstXsdo->drawable, dstGC,
srcx, srcy, width, height, dstx, dsty);
srcXsdo->ReleasePixmapWithBg(env, srcXsdo);
X11SD_DirectRenderNotify(env, dstXsdo);
#endif /* !HEADLESS */
}
/*
* Class: sun_java2d_x11_X11PMBlitLoops
* Method: updateBitmask
* Signature: (Lsun/java2d/SurfaceData;Lsun/java2d/SurfaceData;)V
*/
JNIEXPORT void JNICALL
Java_sun_java2d_x11_X11PMBlitLoops_updateBitmask
(JNIEnv *env, jclass xpmbl, jobject srcsd, jobject dstsd, jboolean isICM)
{
#ifndef HEADLESS
SurfaceDataOps *srcOps = SurfaceData_GetOps(env, srcsd);
X11SDOps *xsdo = (X11SDOps *) SurfaceData_GetOps(env, dstsd);
SurfaceDataRasInfo srcInfo;
int flags;
int screen;
int width;
int height;
jint srcScan, dstScan;
int rowCount;
unsigned char *pDst;
XImage *image;
GC xgc;
if (srcOps == NULL || xsdo == NULL) {
JNU_ThrowNullPointerException(env, "Null BISD in updateMaskRegion");
return;
}
AWT_LOCK();
screen = xsdo->configData->awt_visInfo.screen;
width = xsdo->pmWidth;
height = xsdo->pmHeight;
if (xsdo->bitmask == 0) {
/* create the bitmask if it is not yet created */
xsdo->bitmask = XCreatePixmap(awt_display,
RootWindow(awt_display, screen),
width, height, 1);
if (xsdo->bitmask == 0) {
AWT_UNLOCK();
JNU_ThrowOutOfMemoryError(env,
"Cannot create bitmask for "
"offscreen surface");
return;
}
}
/* Create a bitmask image and then blit it to the pixmap. */
image = XCreateImage(awt_display, DefaultVisual(awt_display, screen),
1, XYBitmap, 0, NULL, width, height, 32, 0);
if (image == NULL) {
AWT_UNLOCK();
JNU_ThrowOutOfMemoryError(env, "Cannot allocate bitmask for mask");
return;
}
dstScan = image->bytes_per_line;
image->data = malloc(dstScan * height);
if (image->data == NULL) {
XFree(image);
AWT_UNLOCK();
JNU_ThrowOutOfMemoryError(env, "Cannot allocate bitmask for mask");
return;
}
pDst = (unsigned char *)image->data;
srcInfo.bounds.x1 = 0;
srcInfo.bounds.y1 = 0;
srcInfo.bounds.x2 = width;
srcInfo.bounds.y2 = height;
flags = (isICM ? (SD_LOCK_LUT | SD_LOCK_READ) : SD_LOCK_READ);
if (srcOps->Lock(env, srcOps, &srcInfo, flags) != SD_SUCCESS) {
XDestroyImage(image);
AWT_UNLOCK();
return;
}
srcOps->GetRasInfo(env, srcOps, &srcInfo);
rowCount = height;
if (isICM) {
unsigned char *pSrc;
jint *srcLut;
srcScan = srcInfo.scanStride;
srcLut = srcInfo.lutBase;
pSrc = (unsigned char *)srcInfo.rasBase;
if (image->bitmap_bit_order == MSBFirst) {
do {
int x = 0, bx = 0;
unsigned int pix = 0;
unsigned int bit = 0x80;
unsigned char *srcPixel = pSrc;
do {
if (bit == 0) {
pDst[bx++] = (unsigned char)pix;
pix = 0;
bit = 0x80;
}
pix |= bit & (srcLut[*srcPixel++] >> 31);
bit >>= 1;
} while (++x < width);
pDst[bx] = (unsigned char)pix;
pDst += dstScan;
pSrc = (unsigned char *) (((intptr_t)pSrc) + srcScan);
} while (--rowCount > 0);
} else {
do {
int x = 0, bx = 0;
unsigned int pix = 0;
unsigned int bit = 1;
unsigned char *srcPixel = pSrc;
do {
if ((bit >> 8) != 0) {
pDst[bx++] = (unsigned char) pix;
pix = 0;
bit = 1;
}
pix |= bit & (srcLut[*srcPixel++] >> 31);
bit <<= 1;
} while (++x < width);
pDst[bx] = (unsigned char) pix;
pDst += dstScan;
pSrc = (unsigned char *) (((intptr_t)pSrc) + srcScan);
} while (--rowCount > 0);
}
} else /*DCM with ARGB*/ {
unsigned int *pSrc;
/* this is a number of pixels in a row, not number of bytes */
srcScan = srcInfo.scanStride;
pSrc = (unsigned int *)srcInfo.rasBase;
if (image->bitmap_bit_order == MSBFirst) {
do {
int x = 0, bx = 0;
unsigned int pix = 0;
unsigned int bit = 0x80;
int *srcPixel = (int *) pSrc;
do {
if (bit == 0) {
/* next word */
pDst[bx++] = (unsigned char)pix;
pix = 0;
bit = 0x80;
}
if (*srcPixel++ & 0xff000000) {
/* if src pixel is opaque, set the bit in the bitmap */
pix |= bit;
}
bit >>= 1;
} while (++x < width);
/* last pixels in a row */
pDst[bx] = (unsigned char)pix;
pDst += dstScan;
pSrc = (unsigned int *) (((intptr_t)pSrc) + srcScan);
} while (--rowCount > 0);
} else {
do {
int x = 0, bx = 0;
unsigned int pix = 0;
unsigned int bit = 1;
int *srcPixel = (int *) pSrc;
do {
if ((bit >> 8) != 0) {
pDst[bx++] = (unsigned char)pix;
pix = 0;
bit = 1;
}
if (*srcPixel++ & 0xff000000) {
/* if src pixel is opaque, set the bit in the bitmap */
pix |= bit;
}
bit <<= 1;
} while (++x < width);
pDst[bx] = (unsigned char)pix;
pDst += dstScan;
pSrc = (unsigned int *) (((intptr_t)pSrc) + srcScan);
} while (--rowCount > 0);
}
}
SurfaceData_InvokeRelease(env, srcOps, &srcInfo);
SurfaceData_InvokeUnlock(env, srcOps, &srcInfo);
xgc = XCreateGC(awt_display, xsdo->bitmask, 0L, NULL);
XSetForeground(awt_display, xgc, 1);
XSetBackground(awt_display, xgc, 0);
XPutImage(awt_display, xsdo->bitmask, xgc,
image, 0, 0, 0, 0, width, height);
XFreeGC(awt_display, xgc);
XDestroyImage(image);
AWT_UNLOCK();
#endif /* !HEADLESS */
}