/*
* Copyright (c) 2000, 2006, 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 "sun_java2d_x11_X11Renderer.h"
#include "X11SurfaceData.h"
#include "SpanIterator.h"
#include "Trace.h"
#include "ProcessPath.h"
#include "GraphicsPrimitiveMgr.h"
#include <jlong.h>
#ifndef HEADLESS
#define POLYTEMPSIZE (int)(256 / sizeof(XPoint))
#define ABS(n) (((n) < 0) ? -(n) : (n))
#define MAX_SHORT 32767
#define MIN_SHORT (-32768)
#define CLAMP_TO_SHORT(x) (((x) > MAX_SHORT) \
? MAX_SHORT \
: ((x) < MIN_SHORT) \
? MIN_SHORT \
: (x))
#define CLAMP_TO_USHORT(x) (((x) > 65535) ? 65535 : ((x) < 0) ? 0 : (x))
#define DF_MAX_XPNTS 256
typedef struct {
Drawable drawable;
GC gc;
XPoint *pPoints;
XPoint dfPoints[DF_MAX_XPNTS];
jint npoints;
jint maxpoints;
} XDrawHandlerData;
#define XDHD_INIT(PTR, _GC, DRAWABLE) \
do { \
(PTR)->pPoints = (PTR)->dfPoints; \
(PTR)->npoints = 0; \
(PTR)->maxpoints = DF_MAX_XPNTS; \
(PTR)->gc = (_GC); \
(PTR)->drawable = (DRAWABLE); \
} while(0)
#define XDHD_RESET(PTR) \
do { \
(PTR)->npoints = 0; \
} while(0)
#define XDHD_ADD_POINT(PTR, X, Y) \
do { \
XPoint* _pnts = (PTR)->pPoints; \
jint _npnts = (PTR)->npoints; \
if (_npnts >= (PTR)->maxpoints) { \
jint newMax = (PTR)->maxpoints*2; \
if ((PTR)->pPoints == (PTR)->dfPoints) { \
(PTR)->pPoints = (XPoint*)malloc(newMax*sizeof(XPoint)); \
memcpy((PTR)->pPoints, _pnts, _npnts*sizeof(XPoint)); \
} else { \
(PTR)->pPoints = (XPoint*)realloc( \
_pnts, newMax*sizeof(XPoint)); \
} \
_pnts = (PTR)->pPoints; \
(PTR)->maxpoints = newMax; \
} \
_pnts += _npnts; \
_pnts->x = X; \
_pnts->y = Y; \
(PTR)->npoints = _npnts + 1; \
} while(0)
#define XDHD_FREE_POINTS(PTR) \
do { \
if ((PTR)->pPoints != (PTR)->dfPoints) { \
free((PTR)->pPoints); \
} \
} while(0)
static void
awt_drawArc(JNIEnv * env, jint drawable, GC xgc,
int x, int y, int w, int h,
int startAngle, int endAngle,
int filled)
{
int s, e;
if (w < 0 || h < 0) {
return;
}
if (endAngle >= 360 || endAngle <= -360) {
s = 0;
e = 360 * 64;
} else {
s = (startAngle % 360) * 64;
e = endAngle * 64;
}
if (filled == 0) {
XDrawArc(awt_display, drawable, xgc, x, y, w, h, s, e);
} else {
XFillArc(awt_display, drawable, xgc, x, y, w, h, s, e);
}
}
/*
* Copy vertices from xcoordsArray and ycoordsArray to a buffer
* of XPoint structures, translating by transx and transy and
* collapsing empty segments out of the list as we go.
* The number of points to be converted should be guaranteed
* to be more than 2 by the caller and is stored at *pNpoints.
* The resulting number of uncollapsed unique translated vertices
* will be stored back into the location *pNpoints.
* The points pointer is guaranteed to be pointing to an area of
* memory large enough for POLYTEMPSIZE points and a larger
* area of memory is allocated (and returned) if that is not enough.
*/
static XPoint *
transformPoints(JNIEnv * env,
jintArray xcoordsArray, jintArray ycoordsArray,
jint transx, jint transy,
XPoint * points, int *pNpoints, int close)
{
int npoints = *pNpoints;
jint *xcoords, *ycoords;
xcoords = (jint *)
(*env)->GetPrimitiveArrayCritical(env, xcoordsArray, NULL);
if (xcoords == NULL) {
return 0;
}
ycoords = (jint *)
(*env)->GetPrimitiveArrayCritical(env, ycoordsArray, NULL);
if (ycoords == NULL) {
(*env)->ReleasePrimitiveArrayCritical(env, xcoordsArray, xcoords,
JNI_ABORT);
return 0;
}
if (close) {
close = (xcoords[npoints - 1] != xcoords[0] ||
ycoords[npoints - 1] != ycoords[0]);
if (close) {
npoints++;
}
}
if (npoints > POLYTEMPSIZE) {
points = (XPoint *) malloc(sizeof(XPoint) * npoints);
}
if (points != NULL) {
int in, out;
int oldx = CLAMP_TO_SHORT(xcoords[0] + transx);
int oldy = CLAMP_TO_SHORT(ycoords[0] + transy);
points[0].x = oldx;
points[0].y = oldy;
if (close) {
npoints--;
}
for (in = 1, out = 1; in < npoints; in++) {
int newx = CLAMP_TO_SHORT(xcoords[in] + transx);
int newy = CLAMP_TO_SHORT(ycoords[in] + transy);
if (newx != oldx || newy != oldy) {
points[out].x = newx;
points[out].y = newy;
out++;
oldx = newx;
oldy = newy;
}
}
if (out == 1) {
points[1].x = oldx;
points[1].y = oldy;
out = 2;
} else if (close) {
points[out++] = points[0];
}
*pNpoints = out;
}
(*env)->ReleasePrimitiveArrayCritical(env, xcoordsArray, xcoords,
JNI_ABORT);
(*env)->ReleasePrimitiveArrayCritical(env, ycoordsArray, ycoords,
JNI_ABORT);
return points;
}
#endif /* !HEADLESS */
/*
* Class: sun_java2d_x11_X11Renderer
* Method: XDrawLine
* Signature: (IJIIII)V
*/
JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XDrawLine
(JNIEnv *env, jobject xr,
jlong pXSData, jlong xgc,
jint x1, jint y1, jint x2, jint y2)
{
#ifndef HEADLESS
X11SDOps *xsdo = (X11SDOps *) pXSData;
if (xsdo == NULL) {
return;
}
XDrawLine(awt_display, xsdo->drawable, (GC) xgc,
CLAMP_TO_SHORT(x1), CLAMP_TO_SHORT(y1),
CLAMP_TO_SHORT(x2), CLAMP_TO_SHORT(y2));
X11SD_DirectRenderNotify(env, xsdo);
#endif /* !HEADLESS */
}
/*
* Class: sun_java2d_x11_X11Renderer
* Method: XDrawRect
* Signature: (IJIIII)V
*/
JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XDrawRect
(JNIEnv *env, jobject xr,
jlong pXSData, jlong xgc,
jint x, jint y, jint w, jint h)
{
#ifndef HEADLESS
X11SDOps *xsdo = (X11SDOps *) pXSData;
if (xsdo == NULL || w < 0 || h < 0) {
return;
}
if (w < 2 || h < 2) {
/* REMIND: This optimization assumes thin lines. */
/*
* This optimization not only simplifies the processing
* of a particular degenerate case, but it protects against
* the anomalies of various X11 implementations that draw
* nothing for degenerate Polygons and Rectangles.
*/
XFillRectangle(awt_display, xsdo->drawable, (GC) xgc,
CLAMP_TO_SHORT(x), CLAMP_TO_SHORT(y),
CLAMP_TO_USHORT(w+1), CLAMP_TO_USHORT(h+1));
} else {
XDrawRectangle(awt_display, xsdo->drawable, (GC) xgc,
CLAMP_TO_SHORT(x), CLAMP_TO_SHORT(y),
CLAMP_TO_USHORT(w), CLAMP_TO_USHORT(h));
}
X11SD_DirectRenderNotify(env, xsdo);
#endif /* !HEADLESS */
}
/*
* Class: sun_java2d_x11_X11Renderer
* Method: XDrawRoundRect
* Signature: (IJIIIIII)V
*/
JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XDrawRoundRect
(JNIEnv *env, jobject xr,
jlong pXSData, jlong xgc,
jint x, jint y, jint w, jint h,
jint arcW, jint arcH)
{
#ifndef HEADLESS
long ty1, ty2, tx1, tx2, cx, cy, cxw, cyh,
halfW, halfH, leftW, rightW, topH, bottomH;
X11SDOps *xsdo = (X11SDOps *) pXSData;
if (xsdo == NULL || w < 0 || h < 0) {
return;
}
arcW = ABS(arcW);
arcH = ABS(arcH);
if (arcW > w) {
arcW = w;
}
if (arcH > h) {
arcH = h;
}
if (arcW == 0 || arcH == 0) {
Java_sun_java2d_x11_X11Renderer_XDrawRect(env, xr, pXSData, xgc,
x, y, w, h);
return;
}
halfW = (arcW / 2);
halfH = (arcH / 2);
/* clamp to short bounding box of round rectangle */
cx = CLAMP_TO_SHORT(x);
cy = CLAMP_TO_SHORT(y);
cxw = CLAMP_TO_SHORT(x + w);
cyh = CLAMP_TO_SHORT(y + h);
/* clamp to short coordinates of lines */
tx1 = CLAMP_TO_SHORT(x + halfW + 1);
tx2 = CLAMP_TO_SHORT(x + w - halfW - 1);
ty1 = CLAMP_TO_SHORT(y + halfH + 1);
ty2 = CLAMP_TO_SHORT(y + h - halfH - 1);
/*
* recalculate heightes and widthes of round parts
* to minimize distortions in visible area
*/
leftW = (tx1 - cx) * 2;
rightW = (cxw - tx2) * 2;
topH = (ty1 - cy) * 2;
bottomH = (cyh - ty2) * 2;
awt_drawArc(env, xsdo->drawable, (GC) xgc,
cx, cy, leftW, topH,
90, 90, JNI_FALSE);
awt_drawArc(env, xsdo->drawable, (GC) xgc,
cxw - rightW, cy, rightW, topH,
0, 90, JNI_FALSE);
awt_drawArc(env, xsdo->drawable, (GC) xgc,
cx, cyh - bottomH, leftW, bottomH,
180, 90, JNI_FALSE);
awt_drawArc(env, xsdo->drawable, (GC) xgc,
cxw - rightW, cyh - bottomH, rightW, bottomH,
270, 90, JNI_FALSE);
if (tx1 <= tx2) {
XDrawLine(awt_display, xsdo->drawable, (GC) xgc,
tx1, cy, tx2, cy);
if (h > 0) {
XDrawLine(awt_display, xsdo->drawable, (GC) xgc,
tx1, cyh, tx2, cyh);
}
}
if (ty1 <= ty2) {
XDrawLine(awt_display, xsdo->drawable, (GC) xgc,
cx, ty1, cx, ty2);
if (w > 0) {
XDrawLine(awt_display, xsdo->drawable, (GC) xgc,
cxw, ty1, cxw, ty2);
}
}
X11SD_DirectRenderNotify(env, xsdo);
#endif /* !HEADLESS */
}
/*
* Class: sun_java2d_x11_X11Renderer
* Method: XDrawOval
* Signature: (IJIIII)V
*/
JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XDrawOval
(JNIEnv *env, jobject xr,
jlong pXSData, jlong xgc,
jint x, jint y, jint w, jint h)
{
#ifndef HEADLESS
X11SDOps *xsdo = (X11SDOps *) pXSData;
if (xsdo == NULL) {
return;
}
if (w < 2 || h < 2) {
/*
* Fix for 4205762 - 1x1 ovals do not draw on Ultra1, Creator3d
* (related to 4411814 on Windows platform)
* Really small ovals degenerate to simple rectangles as they
* have no curvature or enclosed area. Use XFillRectangle
* for speed and to deal better with degenerate sizes.
*/
if (w >= 0 && h >= 0) {
XFillRectangle(awt_display, xsdo->drawable, (GC) xgc,
x, y, w+1, h+1);
}
} else {
awt_drawArc(env, xsdo->drawable, (GC) xgc,
x, y, w, h, 0, 360, JNI_FALSE);
}
X11SD_DirectRenderNotify(env, xsdo);
#endif /* !HEADLESS */
}
/*
* Class: sun_java2d_x11_X11Renderer
* Method: XDrawArc
* Signature: (IJIIIIII)V
*/
JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XDrawArc
(JNIEnv *env, jobject xr,
jlong pXSData, jlong xgc,
jint x, jint y, jint w, jint h,
jint angleStart, jint angleExtent)
{
#ifndef HEADLESS
X11SDOps *xsdo = (X11SDOps *) pXSData;
if (xsdo == NULL) {
return;
}
awt_drawArc(env, xsdo->drawable, (GC) xgc,
x, y, w, h, angleStart, angleExtent, JNI_FALSE);
X11SD_DirectRenderNotify(env, xsdo);
#endif /* !HEADLESS */
}
/*
* Class: sun_java2d_x11_X11Renderer
* Method: XDrawPoly
* Signature: (IJII[I[IIZ)V
*/
JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XDrawPoly
(JNIEnv *env, jobject xr,
jlong pXSData, jlong xgc,
jint transx, jint transy,
jintArray xcoordsArray, jintArray ycoordsArray, jint npoints,
jboolean isclosed)
{
#ifndef HEADLESS
XPoint pTmp[POLYTEMPSIZE], *points;
X11SDOps *xsdo = (X11SDOps *) pXSData;
if (xsdo == NULL) {
return;
}
if (JNU_IsNull(env, xcoordsArray) || JNU_IsNull(env, ycoordsArray)) {
JNU_ThrowNullPointerException(env, "coordinate array");
return;
}
if ((*env)->GetArrayLength(env, ycoordsArray) < npoints ||
(*env)->GetArrayLength(env, xcoordsArray) < npoints)
{
JNU_ThrowArrayIndexOutOfBoundsException(env, "coordinate array");
return;
}
if (npoints < 2) {
return;
}
points = transformPoints(env, xcoordsArray, ycoordsArray, transx, transy,
pTmp, (int *)&npoints, isclosed);
if (points == 0) {
JNU_ThrowOutOfMemoryError(env, "translated coordinate array");
} else {
if (npoints == 2) {
/*
* Some X11 implementations fail to draw anything for
* simple 2 point polygons where the vertices are the
* same point even though this violates the X11
* specification. For simplicity we will dispatch all
* 2 point polygons through XDrawLine even if they are
* non-degenerate as this may invoke less processing
* down the line than a Poly primitive anyway.
*/
XDrawLine(awt_display, xsdo->drawable, (GC) xgc,
points[0].x, points[0].y,
points[1].x, points[1].y);
} else {
XDrawLines(awt_display, xsdo->drawable, (GC) xgc,
points, npoints, CoordModeOrigin);
}
if (points != pTmp) {
free(points);
}
X11SD_DirectRenderNotify(env, xsdo);
}
#endif /* !HEADLESS */
}
static void storeLine(DrawHandler* hnd,
jint x0, jint y0, jint x1, jint y1)
{
#ifndef HEADLESS
XDrawHandlerData* dhnd = (XDrawHandlerData*)(hnd->pData);
XDHD_ADD_POINT(dhnd, x0, y0);
XDHD_ADD_POINT(dhnd, x1, y1);
#endif /* !HEADLESS */
}
static void storePoint(DrawHandler* hnd, jint x0, jint y0) {
#ifndef HEADLESS
XDrawHandlerData* dhnd = (XDrawHandlerData*)(hnd->pData);
XDHD_ADD_POINT(dhnd, x0, y0);
#endif /* !HEADLESS */
}
static void drawSubPath(ProcessHandler* hnd) {
#ifndef HEADLESS
XDrawHandlerData* dhnd = (XDrawHandlerData*)(hnd->dhnd->pData);
XPoint *points = dhnd->pPoints;
switch (dhnd->npoints) {
case 0:
/* No-op */
break;
case 1:
/* Draw the single pixel */
XFillRectangle(awt_display, dhnd->drawable, dhnd->gc,
points[0].x, points[0].y, 1, 1);
break;
case 2:
/*
* The XDrawLines method for some X11 implementations
* fails to draw anything for simple 2 point polygons
* where the vertices are the same point even though
* this violates the X11 specification. For simplicity
* we will dispatch all 2 point polygons through XDrawLine
* even if they are non-degenerate as this may invoke
* less processing down the line than a poly primitive anyway.
*/
XDrawLine(awt_display, dhnd->drawable, dhnd->gc,
points[0].x, points[0].y,
points[1].x, points[1].y);
break;
default:
/* Draw the entire polyline */
XDrawLines(awt_display, dhnd->drawable, dhnd->gc, points,
dhnd->npoints, CoordModeOrigin);
break;
}
XDHD_RESET(dhnd);
#endif /* !HEADLESS */
}
static void drawScanline(DrawHandler* hnd, jint x0, jint x1, jint y0)
{
#ifndef HEADLESS
XDrawHandlerData* dhnd = (XDrawHandlerData*)(hnd->pData);
XDrawLine(awt_display, dhnd->drawable, dhnd->gc, x0, y0, x1, y0);
#endif /* !HEADLESS */
}
/*
* Class: sun_java2d_x11_X11Renderer
* Method: XDoPath
* Signature: (Lsun/java2d/SunGraphics2D;JJIILjava/awt/geom/Path2D/Float;Z)V
*/
JNIEXPORT void JNICALL
Java_sun_java2d_x11_X11Renderer_XDoPath
(JNIEnv *env, jobject self, jobject sg2d, jlong pXSData, jlong xgc,
jint transX, jint transY, jobject p2df, jboolean isFill)
{
#ifndef HEADLESS
X11SDOps *xsdo = (X11SDOps *) pXSData;
jarray typesArray;
jobject pointArray;
jarray coordsArray;
jint numTypes;
jint fillRule;
jint maxCoords;
jbyte *types;
jfloat *coords;
XDrawHandlerData dHData;
DrawHandler drawHandler = {
NULL, NULL, NULL,
MIN_SHORT, MIN_SHORT, MAX_SHORT, MAX_SHORT,
0, 0, 0, 0,
NULL
};
PHStroke stroke;
if (xsdo == NULL) {
return;
}
if (isFill) {
fillRule = (*env)->GetIntField(env, p2df, path2DWindingRuleID);
}
typesArray = (jarray)(*env)->GetObjectField(env, p2df, path2DTypesID);
coordsArray = (jarray)(*env)->GetObjectField(env, p2df,
path2DFloatCoordsID);
if (coordsArray == NULL) {
JNU_ThrowNullPointerException(env, "coordinates array");
return;
}
numTypes = (*env)->GetIntField(env, p2df, path2DNumTypesID);
if ((*env)->GetArrayLength(env, typesArray) < numTypes) {
JNU_ThrowArrayIndexOutOfBoundsException(env, "types array");
return;
}
XDHD_INIT(&dHData, (GC)xgc, xsdo->drawable);
drawHandler.pData = &dHData;
stroke = (((*env)->GetIntField(env, sg2d, sg2dStrokeHintID) ==
sunHints_INTVAL_STROKE_PURE)
? PH_STROKE_PURE
: PH_STROKE_DEFAULT);
maxCoords = (*env)->GetArrayLength(env, coordsArray);
coords = (jfloat*)
(*env)->GetPrimitiveArrayCritical(env, coordsArray, NULL);
if (coords != NULL) {
types = (jbyte*)
(*env)->GetPrimitiveArrayCritical(env, typesArray, NULL);
if (types != NULL) {
jboolean ok;
if (isFill) {
drawHandler.pDrawScanline = &drawScanline;
ok = doFillPath(&drawHandler,
transX, transY,
coords, maxCoords,
types, numTypes,
stroke, fillRule);
} else {
drawHandler.pDrawLine = &storeLine;
drawHandler.pDrawPixel = &storePoint;
ok = doDrawPath(&drawHandler, &drawSubPath,
transX, transY,
coords, maxCoords,
types, numTypes,
stroke);
}
if (!ok) {
JNU_ThrowArrayIndexOutOfBoundsException(env, "coords array");
}
(*env)->ReleasePrimitiveArrayCritical(env, typesArray, types,
JNI_ABORT);
}
(*env)->ReleasePrimitiveArrayCritical(env, coordsArray, coords,
JNI_ABORT);
}
XDHD_FREE_POINTS(&dHData);
X11SD_DirectRenderNotify(env, xsdo);
#endif /* !HEADLESS */
}
/*
* Class: sun_java2d_x11_X11Renderer
* Method: XFillRect
* Signature: (IJIIII)V
*/
JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XFillRect
(JNIEnv *env, jobject xr,
jlong pXSData, jlong xgc,
jint x, jint y, jint w, jint h)
{
#ifndef HEADLESS
X11SDOps *xsdo = (X11SDOps *) pXSData;
if (xsdo == NULL) {
return;
}
XFillRectangle(awt_display, xsdo->drawable, (GC) xgc,
CLAMP_TO_SHORT(x), CLAMP_TO_SHORT(y),
CLAMP_TO_USHORT(w), CLAMP_TO_USHORT(h));
X11SD_DirectRenderNotify(env, xsdo);
#endif /* !HEADLESS */
}
/*
* Class: sun_java2d_x11_X11Renderer
* Method: XFillRoundRect
* Signature: (IJIIIIII)V
*/
JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XFillRoundRect
(JNIEnv *env, jobject xr,
jlong pXSData, jlong xgc,
jint x, jint y, jint w, jint h,
jint arcW, jint arcH)
{
#ifndef HEADLESS
long ty1, ty2, tx1, tx2, cx, cy, cxw, cyh,
halfW, halfH, leftW, rightW, topH, bottomH;
X11SDOps *xsdo = (X11SDOps *) pXSData;
if (xsdo == NULL || w <= 0 || h <= 0) {
return;
}
arcW = ABS(arcW);
arcH = ABS(arcH);
if (arcW > w) {
arcW = w;
}
if (arcH > h) {
arcH = h;
}
if (arcW == 0 || arcH == 0) {
Java_sun_java2d_x11_X11Renderer_XFillRect(env, xr, pXSData, xgc,
x, y, w, h);
return;
}
halfW = (arcW / 2);
halfH = (arcH / 2);
/* clamp to short bounding box of round rectangle */
cx = CLAMP_TO_SHORT(x);
cy = CLAMP_TO_SHORT(y);
cxw = CLAMP_TO_SHORT(x + w);
cyh = CLAMP_TO_SHORT(y + h);
/* clamp to short coordinates of lines */
tx1 = CLAMP_TO_SHORT(x + halfW + 1);
tx2 = CLAMP_TO_SHORT(x + w - halfW - 1);
ty1 = CLAMP_TO_SHORT(y + halfH + 1);
ty2 = CLAMP_TO_SHORT(y + h - halfH - 1);
/*
* recalculate heightes and widthes of round parts
* to minimize distortions in visible area
*/
leftW = (tx1 - cx) * 2;
rightW = (cxw - tx2) * 2;
topH = (ty1 - cy) * 2;
bottomH = (cyh - ty2) * 2;
awt_drawArc(env, xsdo->drawable, (GC) xgc,
cx, cy, leftW, topH,
90, 90, JNI_TRUE);
awt_drawArc(env, xsdo->drawable, (GC) xgc,
cxw - rightW, cy, rightW, topH,
0, 90, JNI_TRUE);
awt_drawArc(env, xsdo->drawable, (GC) xgc,
cx, cyh - bottomH, leftW, bottomH,
180, 90, JNI_TRUE);
awt_drawArc(env, xsdo->drawable, (GC) xgc,
cxw - rightW, cyh - bottomH, rightW, bottomH,
270, 90, JNI_TRUE);
if (tx1 < tx2) {
if (cy < ty1) {
XFillRectangle(awt_display, xsdo->drawable, (GC) xgc,
tx1, cy, tx2 - tx1, ty1 - cy);
}
if (ty2 < cyh) {
XFillRectangle(awt_display, xsdo->drawable, (GC) xgc,
tx1, ty2, tx2 - tx1, cyh - ty2);
}
}
if (ty1 < ty2) {
XFillRectangle(awt_display, xsdo->drawable, (GC) xgc,
cx, ty1, cxw - cx, ty2 - ty1);
}
X11SD_DirectRenderNotify(env, xsdo);
#endif /* !HEADLESS */
}
/*
* Class: sun_java2d_x11_X11Renderer
* Method: XFillOval
* Signature: (IJIIII)V
*/
JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XFillOval
(JNIEnv *env, jobject xr,
jlong pXSData, jlong xgc,
jint x, jint y, jint w, jint h)
{
#ifndef HEADLESS
X11SDOps *xsdo = (X11SDOps *) pXSData;
if (xsdo == NULL) {
return;
}
if (w < 3 || h < 3) {
/*
* Fix for 4205762 - 1x1 ovals do not draw on Ultra1, Creator3d
* (related to 4411814 on Windows platform)
* Most X11 servers drivers have poor rendering
* for thin ellipses and the rendering is most strikingly
* different from our theoretical arcs. Ideally we should
* trap all ovals less than some fairly large size and
* try to draw aesthetically pleasing ellipses, but that
* would require considerably more work to get the corresponding
* drawArc variants to match pixel for pixel.
* Thin ovals of girth 1 pixel are simple rectangles.
* Thin ovals of girth 2 pixels are simple rectangles with
* potentially smaller lengths. Determine the correct length
* by calculating .5*.5 + scaledlen*scaledlen == 1.0 which
* means that scaledlen is the sqrt(0.75). Scaledlen is
* relative to the true length (w or h) and needs to be
* adjusted by half a pixel in different ways for odd or
* even lengths.
*/
#define SQRT_3_4 0.86602540378443864676
if (w > 2 && h > 1) {
int adjw = (int) ((SQRT_3_4 * w - ((w&1)-1)) * 0.5);
adjw = adjw * 2 + (w&1);
x += (w-adjw)/2;
w = adjw;
} else if (h > 2 && w > 1) {
int adjh = (int) ((SQRT_3_4 * h - ((h&1)-1)) * 0.5);
adjh = adjh * 2 + (h&1);
y += (h-adjh)/2;
h = adjh;
}
#undef SQRT_3_4
if (w > 0 && h > 0) {
XFillRectangle(awt_display, xsdo->drawable, (GC) xgc, x, y, w, h);
}
} else {
awt_drawArc(env, xsdo->drawable, (GC) xgc,
x, y, w, h, 0, 360, JNI_TRUE);
}
X11SD_DirectRenderNotify(env, xsdo);
#endif /* !HEADLESS */
}
/*
* Class: sun_java2d_x11_X11Renderer
* Method: XFillArc
* Signature: (IJIIIIII)V
*/
JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XFillArc
(JNIEnv *env, jobject xr,
jlong pXSData, jlong xgc,
jint x, jint y, jint w, jint h,
jint angleStart, jint angleExtent)
{
#ifndef HEADLESS
X11SDOps *xsdo = (X11SDOps *) pXSData;
if (xsdo == NULL) {
return;
}
awt_drawArc(env, xsdo->drawable, (GC) xgc,
x, y, w, h, angleStart, angleExtent, JNI_TRUE);
X11SD_DirectRenderNotify(env, xsdo);
#endif /* !HEADLESS */
}
/*
* Class: sun_java2d_x11_X11Renderer
* Method: XFillPoly
* Signature: (IJII[I[II)V
*/
JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XFillPoly
(JNIEnv *env, jobject xr,
jlong pXSData, jlong xgc,
jint transx, jint transy,
jintArray xcoordsArray, jintArray ycoordsArray, jint npoints)
{
#ifndef HEADLESS
XPoint pTmp[POLYTEMPSIZE], *points;
X11SDOps *xsdo = (X11SDOps *) pXSData;
if (xsdo == NULL) {
return;
}
if (JNU_IsNull(env, xcoordsArray) || JNU_IsNull(env, ycoordsArray)) {
JNU_ThrowNullPointerException(env, "coordinate array");
return;
}
if ((*env)->GetArrayLength(env, ycoordsArray) < npoints ||
(*env)->GetArrayLength(env, xcoordsArray) < npoints)
{
JNU_ThrowArrayIndexOutOfBoundsException(env, "coordinate array");
return;
}
if (npoints < 3) {
return;
}
points = transformPoints(env, xcoordsArray, ycoordsArray, transx, transy,
pTmp, (int *)&npoints, JNI_FALSE);
if (points == 0) {
JNU_ThrowOutOfMemoryError(env, "translated coordinate array");
} else {
if (npoints > 2) {
XFillPolygon(awt_display, xsdo->drawable, (GC) xgc,
points, npoints, Complex, CoordModeOrigin);
X11SD_DirectRenderNotify(env, xsdo);
}
if (points != pTmp) {
free(points);
}
}
#endif /* !HEADLESS */
}
/*
* Class: sun_java2d_x11_X11Renderer
* Method: XFillSpans
* Signature: (IJLsun/java2d/pipe/SpanIterator;JII)V
*/
JNIEXPORT void JNICALL Java_sun_java2d_x11_X11Renderer_XFillSpans
(JNIEnv *env, jobject xr,
jlong pXSData, jlong xgc,
jobject si, jlong pIterator,
jint transx, jint transy)
{
#ifndef HEADLESS
SpanIteratorFuncs *pFuncs = (SpanIteratorFuncs *) jlong_to_ptr(pIterator);
void *srData;
jint x, y, w, h;
jint spanbox[4];
X11SDOps *xsdo = (X11SDOps *) pXSData;
if (xsdo == NULL) {
return;
}
if (JNU_IsNull(env, si)) {
JNU_ThrowNullPointerException(env, "span iterator");
return;
}
if (pFuncs == NULL) {
JNU_ThrowNullPointerException(env, "native iterator not supplied");
return;
}
srData = (*pFuncs->open)(env, si);
while ((*pFuncs->nextSpan)(srData, spanbox)) {
x = spanbox[0] + transx;
y = spanbox[1] + transy;
w = spanbox[2] - spanbox[0];
h = spanbox[3] - spanbox[1];
XFillRectangle(awt_display, xsdo->drawable, (GC) xgc,
CLAMP_TO_SHORT(x), CLAMP_TO_SHORT(y),
CLAMP_TO_USHORT(w), CLAMP_TO_USHORT(h));
}
(*pFuncs->close)(env, srData);
X11SD_DirectRenderNotify(env, xsdo);
#endif /* !HEADLESS */
}
/*
* Class: sun_java2d_x11_X11Renderer
* Method: devCopyArea
* Signature: (Lsun/java2d/SurfaceData;IIIIII)V
*/
JNIEXPORT void JNICALL
Java_sun_java2d_x11_X11Renderer_devCopyArea
(JNIEnv *env, jobject xr,
jlong xsd, jlong gc,
jint srcx, jint srcy,
jint dstx, jint dsty,
jint width, jint height)
{
#ifndef HEADLESS
X11SDOps *xsdo;
GC xgc;
xsdo = (X11SDOps *)jlong_to_ptr(xsd);
if (xsdo == NULL) {
return;
}
xgc = (GC)gc;
if (xgc == NULL) {
return;
}
XCopyArea(awt_display, xsdo->drawable, xsdo->drawable, xgc,
srcx, srcy, width, height, dstx, dsty);
X11SD_DirectRenderNotify(env, xsdo);
#endif /* !HEADLESS */
}