| /* | |
| * Copyright (c) 2000, 2024, 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) { | |
| 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; | |
| 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; | |
| jboolean ok = JNI_TRUE; | |
| 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) { | |
| 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); | |
| } | |
| (*env)->ReleasePrimitiveArrayCritical(env, typesArray, types, | |
| JNI_ABORT); | |
| } | |
| (*env)->ReleasePrimitiveArrayCritical(env, coordsArray, coords, | |
| JNI_ABORT); | |
| if (!ok) { | |
| JNU_ThrowArrayIndexOutOfBoundsException(env, "coords array"); | |
| } | |
| } | |
| 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) { | |
| 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 */ | |
| } |