| /* |
| * Copyright (c) 1999, 2018, 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 "jni_util.h" |
| #include "awt.h" |
| #include "sun_java2d_windows_GDIRenderer.h" |
| #include "java_awt_geom_PathIterator.h" |
| |
| #include "GDIWindowSurfaceData.h" |
| #include "awt_Component.h" |
| #include "awt_Pen.h" |
| #include "awt_Brush.h" |
| |
| #include "GraphicsPrimitiveMgr.h" |
| |
| #include <math.h> /* for cos(), sin(), etc */ |
| |
| #define MAX_CLAMP_BND (1<<26) |
| #define MIN_CLAMP_BND (-MAX_CLAMP_BND) |
| |
| #define CLAMP(x) (((x) > MAX_CLAMP_BND) ? \ |
| MAX_CLAMP_BND : ((x) < MIN_CLAMP_BND) ? \ |
| MIN_CLAMP_BND : (x)) |
| |
| |
| extern "C" { |
| |
| #define POLYTEMPSIZE (512 / sizeof(POINT)) |
| |
| static void AngleToCoord(jint angle, jint w, jint h, jint *x, jint *y) |
| { |
| const double pi = 3.1415926535; |
| const double toRadians = 2 * pi / 360; |
| |
| *x = (long)(cos((double)angle * toRadians) * w); |
| *y = -(long)(sin((double)angle * toRadians) * h); |
| } |
| |
| static POINT *TransformPoly(jint *xpoints, jint *ypoints, |
| jint transx, jint transy, |
| POINT *pPoints, jint *pNpoints, |
| BOOL close, BOOL fixend) |
| { |
| int npoints = *pNpoints; |
| int outpoints = npoints; |
| jint x, y; |
| |
| // Fix for 4298688 - draw(Line) and Polygon omit last pixel |
| // We will need to add a point if we need to close it off or |
| // if we need to fix the endpoint to accommodate the Windows |
| // habit of never drawing the last pixel of a Polyline. Note |
| // that if the polyline is already closed then neither fix |
| // is needed because the last pixel is also the first pixel |
| // and so will be drawn just fine. |
| // Clarification for 4298688 - regression bug 4678208 points |
| // out that we still need to fix the endpoint if the closed |
| // polygon never went anywhere (all vertices on same coordinate). |
| jint mx = xpoints[0]; |
| jint my = ypoints[0]; |
| BOOL isclosed = (xpoints[npoints-1] == mx && ypoints[npoints-1] == my); |
| if ((close && !isclosed) || fixend) { |
| outpoints++; |
| *pNpoints = outpoints; |
| } |
| if (outpoints > POLYTEMPSIZE) { |
| try { |
| pPoints = (POINT *) SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, sizeof(POINT), outpoints); |
| } catch (const std::bad_alloc&) { |
| return NULL; |
| } |
| } |
| BOOL isempty = fixend; |
| for (int i = 0; i < npoints; i++) { |
| x = xpoints[i]; |
| y = ypoints[i]; |
| isempty = isempty && (x == mx && y == my); |
| pPoints[i].x = CLAMP(x + transx); |
| pPoints[i].y = CLAMP(y + transy); |
| } |
| if (close && !isclosed) { |
| pPoints[npoints] = pPoints[0]; |
| } else if (fixend) { |
| if (!close || isempty) { |
| // Fix for 4298688 - draw(Line) and Polygon omit last pixel |
| // Fix up the last segment by adding another segment after |
| // it that is only 1 pixel long. The first pixel of that |
| // segment will be drawn, but the second pixel is the one |
| // that Windows omits. |
| pPoints[npoints] = pPoints[npoints-1]; |
| pPoints[npoints].x++; |
| } else { |
| outpoints--; |
| *pNpoints = outpoints; |
| } |
| } |
| |
| return pPoints; |
| } |
| |
| /* |
| * Class: sun_java2d_windows_GDIRenderer |
| * Method: doDrawLine |
| * Signature: (Lsun/java2d/windows/GDIWindowSurfaceData;Lsun/java2d/pipe/Region;Ljava/awt/Composite;IIIII)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_java2d_windows_GDIRenderer_doDrawLine |
| (JNIEnv *env, jobject wr, |
| jobject sData, |
| jobject clip, jobject comp, jint color, |
| jint x1, jint y1, jint x2, jint y2) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "GDIRenderer_doDrawLine"); |
| J2dTraceLn5(J2D_TRACE_VERBOSE, |
| " color=0x%x x1=%-4d y1=%-4d x2=%-4d y2=%-4d", |
| color, x1, y1, x2, y2); |
| GDIWinSDOps *wsdo = GDIWindowSurfaceData_GetOps(env, sData); |
| if (wsdo == NULL) { |
| return; |
| } |
| |
| HDC hdc; |
| jint patrop; |
| if (x1 == x2 || y1 == y2) { |
| if (x1 > x2) { |
| jint t = x1; x1 = x2; x2 = t; |
| } |
| if (y1 > y2) { |
| jint t = y1; y1 = y2; y2 = t; |
| } |
| hdc = wsdo->GetDC(env, wsdo, BRUSH, &patrop, clip, comp, color); |
| if (hdc == NULL) { |
| return; |
| } |
| ::PatBlt(hdc, x1, y1, x2-x1+1, y2-y1+1, patrop); |
| } else { |
| hdc = wsdo->GetDC(env, wsdo, PENBRUSH, &patrop, clip, comp, color); |
| if (hdc == NULL) { |
| return; |
| } |
| ::MoveToEx(hdc, x1, y1, NULL); |
| ::LineTo(hdc, x2, y2); |
| ::PatBlt(hdc, x2, y2, 1, 1, patrop); |
| } |
| wsdo->ReleaseDC(env, wsdo, hdc); |
| } |
| |
| /* |
| * Class: sun_java2d_windows_GDIRenderer |
| * Method: doDrawRect |
| * Signature: (Lsun/java2d/windows/GDIWindowSurfaceData;Lsun/java2d/pipe/Region;Ljava/awt/Composite;IIIII)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_java2d_windows_GDIRenderer_doDrawRect |
| (JNIEnv *env, jobject wr, |
| jobject sData, |
| jobject clip, jobject comp, jint color, |
| jint x, jint y, jint w, jint h) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "GDIRenderer_doDrawRect"); |
| J2dTraceLn5(J2D_TRACE_VERBOSE, |
| " color=0x%x x=%-4d y=%-4d w=%-4d h=%-4d", |
| color, x, y, w, h); |
| if (w < 0 || h < 0) { |
| return; |
| } |
| |
| GDIWinSDOps *wsdo = GDIWindowSurfaceData_GetOps(env, sData); |
| if (wsdo == NULL) { |
| return; |
| } |
| jint patrop; |
| HDC hdc = wsdo->GetDC(env, wsdo, BRUSH, &patrop, clip, comp, color); |
| if (hdc == NULL) { |
| return; |
| } |
| if (w < 2 || h < 2) { |
| // If one dimension is less than 2 then there is no |
| // gap in the middle - draw a solid filled rectangle. |
| ::PatBlt(hdc, x, y, w+1, h+1, patrop); |
| } else { |
| // Avoid drawing the endpoints twice. |
| // Also prefer including the endpoints in the |
| // horizontal sections which draw pixels faster. |
| ::PatBlt(hdc, x, y, w+1, 1, patrop); |
| ::PatBlt(hdc, x, y+1, 1, h-1, patrop); |
| ::PatBlt(hdc, x+w, y+1, 1, h-1, patrop); |
| ::PatBlt(hdc, x, y+h, w+1, 1, patrop); |
| } |
| wsdo->ReleaseDC(env, wsdo, hdc); |
| } |
| |
| /* |
| * Class: sun_java2d_windows_GDIRenderer |
| * Method: doDrawRoundRect |
| * Signature: (Lsun/java2d/windows/GDIWindowSurfaceData;Lsun/java2d/pipe/Region;Ljava/awt/Composite;IIIIIII)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_java2d_windows_GDIRenderer_doDrawRoundRect |
| (JNIEnv *env, jobject wr, |
| jobject sData, |
| jobject clip, jobject comp, jint color, |
| jint x, jint y, jint w, jint h, jint arcW, jint arcH) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "GDIRenderer_doDrawRoundRect"); |
| J2dTraceLn5(J2D_TRACE_VERBOSE, |
| " color=0x%x x=%-4d y=%-4d w=%-4d h=%-4d", |
| color, x, y, w, h); |
| J2dTraceLn2(J2D_TRACE_VERBOSE, " arcW=%-4d arcH=%-4d", |
| arcW, arcH); |
| if (w < 2 || h < 2 || arcW <= 0 || arcH <= 0) { |
| // Fix for 4524760 - drawRoundRect0 test case fails on Windows 98 |
| // Thin round rects degenerate into regular rectangles |
| // because there is no room for the arc sections. Also |
| // if there is no arc dimension then the roundrect must |
| // be a simple rectangle. Defer to the DrawRect function |
| // which handles degenerate sizes better. |
| Java_sun_java2d_windows_GDIRenderer_doDrawRect(env, wr, |
| sData, clip, |
| comp, color, |
| x, y, w, h); |
| return; |
| } |
| |
| GDIWinSDOps *wsdo = GDIWindowSurfaceData_GetOps(env, sData); |
| if (wsdo == NULL) { |
| return; |
| } |
| HDC hdc = wsdo->GetDC(env, wsdo, PENONLY, NULL, clip, comp, color); |
| if (hdc == NULL) { |
| return; |
| } |
| ::RoundRect(hdc, x, y, x+w+1, y+h+1, arcW, arcH); |
| wsdo->ReleaseDC(env, wsdo, hdc); |
| } |
| |
| /* |
| * Class: sun_java2d_windows_GDIRenderer |
| * Method: doDrawOval |
| * Signature: (Lsun/java2d/windows/GDIWindowSurfaceData;Lsun/java2d/pipe/Region;Ljava/awt/Composite;IIIII)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_java2d_windows_GDIRenderer_doDrawOval |
| (JNIEnv *env, jobject wr, |
| jobject sData, |
| jobject clip, jobject comp, jint color, |
| jint x, jint y, jint w, jint h) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "GDIRenderer_doDrawOval"); |
| J2dTraceLn5(J2D_TRACE_VERBOSE, |
| " color=0x%x x=%-4d y=%-4d w=%-4d h=%-4d", |
| color, x, y, w, h); |
| if (w < 2 || h < 2) { |
| // Thin enough ovals have no room for curvature. Defer to |
| // the DrawRect method which handles degenerate sizes better. |
| Java_sun_java2d_windows_GDIRenderer_doDrawRect(env, wr, |
| sData, clip, |
| comp, color, |
| x, y, w, h); |
| return; |
| } |
| |
| GDIWinSDOps *wsdo = GDIWindowSurfaceData_GetOps(env, sData); |
| if (wsdo == NULL) { |
| return; |
| } |
| HDC hdc = wsdo->GetDC(env, wsdo, PENONLY, NULL, clip, comp, color); |
| if (hdc == NULL) { |
| return; |
| } |
| ::Ellipse(hdc, x, y, x+w+1, y+h+1); |
| wsdo->ReleaseDC(env, wsdo, hdc); |
| } |
| |
| /* |
| * Class: sun_java2d_windows_GDIRenderer |
| * Method: doDrawArc |
| * Signature: (Lsun/java2d/windows/GDIWindowSurfaceData;Lsun/java2d/pipe/Region;Ljava/awt/Composite;IIIIIII)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_java2d_windows_GDIRenderer_doDrawArc |
| (JNIEnv *env, jobject wr, |
| jobject sData, |
| jobject clip, jobject comp, jint color, |
| jint x, jint y, jint w, jint h, |
| jint angleStart, jint angleExtent) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "GDIRenderer_doDrawArc"); |
| J2dTraceLn5(J2D_TRACE_VERBOSE, |
| " color=0x%x x=%-4d y=%-4d w=%-4d h=%-4d", |
| color, x, y, w, h); |
| J2dTraceLn2(J2D_TRACE_VERBOSE, |
| " angleStart=%-4d angleExtent=%-4d", |
| angleStart, angleExtent); |
| if (w < 0 || h < 0 || angleExtent == 0) { |
| return; |
| } |
| |
| GDIWinSDOps *wsdo = GDIWindowSurfaceData_GetOps(env, sData); |
| if (wsdo == NULL) { |
| return; |
| } |
| |
| long sx, sy, ex, ey; |
| if (angleExtent >= 360 || angleExtent <= -360) { |
| sx = ex = x + w; |
| sy = ey = y + h/2; |
| } else { |
| int angleEnd; |
| if (angleExtent < 0) { |
| angleEnd = angleStart; |
| angleStart += angleExtent; |
| } else { |
| angleEnd = angleStart + angleExtent; |
| } |
| AngleToCoord(angleStart, w, h, &sx, &sy); |
| sx += x + w/2; |
| sy += y + h/2; |
| AngleToCoord(angleEnd, w, h, &ex, &ey); |
| ex += x + w/2; |
| ey += y + h/2; |
| } |
| HDC hdc = wsdo->GetDC(env, wsdo, PEN, NULL, clip, comp, color); |
| if (hdc == NULL) { |
| return; |
| } |
| ::Arc(hdc, x, y, x+w+1, y+h+1, sx, sy, ex, ey); |
| wsdo->ReleaseDC(env, wsdo, hdc); |
| } |
| |
| /* |
| * Class: sun_java2d_windows_GDIRenderer |
| * Method: doDrawPoly |
| * Signature: (Lsun/java2d/windows/GDIWindowSurfaceData;Lsun/java2d/pipe/Region;Ljava/awt/Composite;III[I[IIZ)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_java2d_windows_GDIRenderer_doDrawPoly |
| (JNIEnv *env, jobject wr, |
| jobject sData, |
| jobject clip, jobject comp, jint color, |
| jint transx, jint transy, |
| jintArray xpointsarray, jintArray ypointsarray, |
| jint npoints, jboolean isclosed) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "GDIRenderer_doDrawPoly"); |
| J2dTraceLn5(J2D_TRACE_VERBOSE, |
| " color=0x%x transx=%-4d transy=%-4d "\ |
| "npoints=%-4d isclosed=%-4d", |
| color, transx, transy, npoints, isclosed); |
| if (JNU_IsNull(env, xpointsarray) || JNU_IsNull(env, ypointsarray)) { |
| JNU_ThrowNullPointerException(env, "coordinate array"); |
| return; |
| } |
| if (env->GetArrayLength(xpointsarray) < npoints || |
| env->GetArrayLength(ypointsarray) < npoints) |
| { |
| JNU_ThrowArrayIndexOutOfBoundsException(env, "coordinate array"); |
| return; |
| } |
| if (npoints < 2) { |
| // Fix for 4067534 - assertion failure in 1.3.1 for degenerate polys |
| // Not enough points for a line. |
| // Note that this would be ignored later anyway, but returning |
| // here saves us from mistakes in TransformPoly and seeing bad |
| // return values from the Windows Polyline function. |
| return; |
| } |
| |
| GDIWinSDOps *wsdo = GDIWindowSurfaceData_GetOps(env, sData); |
| if (wsdo == NULL) { |
| return; |
| } |
| |
| POINT tmpPts[POLYTEMPSIZE], *pPoints = NULL; |
| |
| jint *xpoints = (jint *) env->GetPrimitiveArrayCritical(xpointsarray, NULL); |
| |
| if (xpoints != NULL) { |
| jint *ypoints = (jint *) env->GetPrimitiveArrayCritical(ypointsarray, NULL); |
| if (ypoints != NULL) { |
| pPoints = TransformPoly(xpoints, ypoints, transx, transy, |
| tmpPts, &npoints, isclosed, TRUE); |
| env->ReleasePrimitiveArrayCritical(ypointsarray, ypoints, JNI_ABORT); |
| } |
| env->ReleasePrimitiveArrayCritical(xpointsarray, xpoints, JNI_ABORT); |
| } |
| |
| if (pPoints == NULL) { |
| return; |
| } |
| |
| HDC hdc = wsdo->GetDC(env, wsdo, PEN, NULL, clip, comp, color); |
| if (hdc == NULL) { |
| return; |
| } |
| ::Polyline(hdc, pPoints, npoints); |
| wsdo->ReleaseDC(env, wsdo, hdc); |
| if (pPoints != tmpPts) { |
| free(pPoints); |
| } |
| } |
| |
| /* |
| * Class: sun_java2d_windows_GDIRenderer |
| * Method: doFillRect |
| * Signature: (Lsun/java2d/windows/GDIWindowSurfaceData;Lsun/java2d/pipe/Region;Ljava/awt/Composite;IIIII)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_java2d_windows_GDIRenderer_doFillRect |
| (JNIEnv *env, jobject wr, |
| jobject sData, |
| jobject clip, jobject comp, jint color, |
| jint x, jint y, jint w, jint h) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "GDIRenderer_doFillRect"); |
| J2dTraceLn5(J2D_TRACE_VERBOSE, |
| " color=0x%x x=%-4d y=%-4d w=%-4d h=%-4d", |
| color, x, y, w, h); |
| if (w <= 0 || h <= 0) { |
| return; |
| } |
| |
| GDIWinSDOps *wsdo = GDIWindowSurfaceData_GetOps(env, sData); |
| if (wsdo == NULL) { |
| return; |
| } |
| jint patrop; |
| HDC hdc = wsdo->GetDC(env, wsdo, BRUSH, &patrop, clip, comp, color); |
| if (hdc == NULL) { |
| return; |
| } |
| ::PatBlt(hdc, x, y, w, h, patrop); |
| wsdo->ReleaseDC(env, wsdo, hdc); |
| } |
| |
| /* |
| * Class: sun_java2d_windows_GDIRenderer |
| * Method: doFillRoundRect |
| * Signature: (Lsun/java2d/windows/GDIWindowSurfaceData;Lsun/java2d/pipe/Region;Ljava/awt/Composite;IIIIIII)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_java2d_windows_GDIRenderer_doFillRoundRect |
| (JNIEnv *env, jobject wr, |
| jobject sData, |
| jobject clip, jobject comp, jint color, |
| jint x, jint y, jint w, jint h, jint arcW, jint arcH) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "GDIRenderer_doFillRoundRect"); |
| J2dTraceLn5(J2D_TRACE_VERBOSE, |
| " color=0x%x x=%-4d y=%-4d w=%-4d h=%-4d", |
| color, x, y, w, h); |
| J2dTraceLn2(J2D_TRACE_VERBOSE, " arcW=%-4d arcH=%-4d", |
| arcW, arcH); |
| if (w < 2 || h < 2 || arcW <= 0 || arcH <= 0) { |
| // Fix related to 4524760 - drawRoundRect0 fails on Windows 98 |
| // Thin round rects have no room for curvature. Also, if |
| // the curvature is empty then the primitive has degenerated |
| // into a simple rectangle. Defer to the FillRect method |
| // which deals with degenerate sizes better. |
| Java_sun_java2d_windows_GDIRenderer_doFillRect(env, wr, |
| sData, clip, |
| comp, color, |
| x, y, w, h); |
| return; |
| } |
| |
| GDIWinSDOps *wsdo = GDIWindowSurfaceData_GetOps(env, sData); |
| if (wsdo == NULL) { |
| return; |
| } |
| HDC hdc = wsdo->GetDC(env, wsdo, BRUSHONLY, NULL, clip, comp, color); |
| if (hdc == NULL) { |
| return; |
| } |
| ::RoundRect(hdc, x, y, x+w+1, y+h+1, arcW, arcH); |
| wsdo->ReleaseDC(env, wsdo, hdc); |
| } |
| |
| /* |
| * Class: sun_java2d_windows_GDIRenderer |
| * Method: doFillOval |
| * Signature: (Lsun/java2d/windows/GDIWindowSurfaceData;Lsun/java2d/pipe/Region;Ljava/awt/Composite;IIIII)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_java2d_windows_GDIRenderer_doFillOval |
| (JNIEnv *env, jobject wr, |
| jobject sData, |
| jobject clip, jobject comp, jint color, |
| jint x, jint y, jint w, jint h) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "GDIRenderer_doFillOval"); |
| J2dTraceLn5(J2D_TRACE_VERBOSE, |
| " color=0x%x x=%-4d y=%-4d w=%-4d h=%-4d", |
| color, x, y, w, h); |
| if (w < 3 || h < 3) { |
| // Fix for 4411814 - small ovals do not draw anything |
| // (related to 4205762 on Solaris platform) |
| // Most platform graphics packages 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) { |
| Java_sun_java2d_windows_GDIRenderer_doFillRect(env, wr, sData, |
| clip, comp, color, |
| x, y, w, h); |
| } |
| return; |
| } |
| |
| GDIWinSDOps *wsdo = GDIWindowSurfaceData_GetOps(env, sData); |
| if (wsdo == NULL) { |
| return; |
| } |
| HDC hdc = wsdo->GetDC(env, wsdo, BRUSHONLY, NULL, clip, comp, color); |
| if (hdc == NULL) { |
| return; |
| } |
| ::Ellipse(hdc, x, y, x+w+1, y+h+1); |
| wsdo->ReleaseDC(env, wsdo, hdc); |
| } |
| |
| /* |
| * Class: sun_java2d_windows_GDIRenderer |
| * Method: doFillArc |
| * Signature: (Lsun/java2d/windows/GDIWindowSurfaceData;Lsun/java2d/pipe/Region;Ljava/awt/Composite;IIIIIII)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_java2d_windows_GDIRenderer_doFillArc |
| (JNIEnv *env, jobject wr, |
| jobject sData, |
| jobject clip, jobject comp, jint color, |
| jint x, jint y, jint w, jint h, |
| jint angleStart, jint angleExtent) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "GDIRenderer_doFillArc"); |
| J2dTraceLn5(J2D_TRACE_VERBOSE, |
| " color=0x%x x=%-4d y=%-4d w=%-4d h=%-4d", |
| color, x, y, w, h); |
| J2dTraceLn2(J2D_TRACE_VERBOSE, |
| " angleStart=%-4d angleExtent=%-4d", |
| angleStart, angleExtent); |
| if (w <= 0 || h <= 0 || angleExtent == 0) { |
| return; |
| } |
| if (angleExtent >= 360 || angleExtent <= -360) { |
| // Fix related to 4411814 - small ovals (and arcs) do not draw |
| // If the arc is a full circle, let the Oval method handle it |
| // since that method can deal with degenerate sizes better. |
| Java_sun_java2d_windows_GDIRenderer_doFillOval(env, wr, |
| sData, clip, |
| comp, color, |
| x, y, w, h); |
| return; |
| } |
| |
| GDIWinSDOps *wsdo = GDIWindowSurfaceData_GetOps(env, sData); |
| if (wsdo == NULL) { |
| return; |
| } |
| long sx, sy, ex, ey; |
| int angleEnd; |
| if (angleExtent < 0) { |
| angleEnd = angleStart; |
| angleStart += angleExtent; |
| } else { |
| angleEnd = angleStart + angleExtent; |
| } |
| AngleToCoord(angleStart, w, h, &sx, &sy); |
| sx += x + w/2; |
| sy += y + h/2; |
| AngleToCoord(angleEnd, w, h, &ex, &ey); |
| ex += x + w/2; |
| ey += y + h/2; |
| HDC hdc = wsdo->GetDC(env, wsdo, BRUSHONLY, NULL, clip, comp, color); |
| if (hdc == NULL) { |
| return; |
| } |
| ::Pie(hdc, x, y, x+w+1, y+h+1, sx, sy, ex, ey); |
| wsdo->ReleaseDC(env, wsdo, hdc); |
| } |
| |
| /* |
| * Class: sun_java2d_windows_GDIRenderer |
| * Method: doFillPoly |
| * Signature: (Lsun/java2d/windows/GDIWindowSurfaceData;Lsun/java2d/pipe/Region;Ljava/awt/Composite;III[I[II)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_java2d_windows_GDIRenderer_doFillPoly |
| (JNIEnv *env, jobject wr, |
| jobject sData, |
| jobject clip, jobject comp, jint color, |
| jint transx, jint transy, |
| jintArray xpointsarray, jintArray ypointsarray, |
| jint npoints) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "GDIRenderer_doFillPoly"); |
| J2dTraceLn4(J2D_TRACE_VERBOSE, |
| " color=0x%x transx=%-4d transy=%-4d npoints=%-4d", |
| color, transx, transy, npoints); |
| if (JNU_IsNull(env, xpointsarray) || JNU_IsNull(env, ypointsarray)) { |
| JNU_ThrowNullPointerException(env, "coordinate array"); |
| return; |
| } |
| if (env->GetArrayLength(xpointsarray) < npoints || |
| env->GetArrayLength(ypointsarray) < npoints) |
| { |
| JNU_ThrowArrayIndexOutOfBoundsException(env, "coordinate array"); |
| return; |
| } |
| if (npoints < 3) { |
| // Fix for 4067534 - assertion failure in 1.3.1 for degenerate polys |
| // Not enough points for a triangle. |
| // Note that this would be ignored later anyway, but returning |
| // here saves us from mistakes in TransformPoly and seeing bad |
| // return values from the Windows Polyline function. |
| return; |
| } |
| |
| GDIWinSDOps *wsdo = GDIWindowSurfaceData_GetOps(env, sData); |
| if (wsdo == NULL) { |
| return; |
| } |
| |
| POINT tmpPts[POLYTEMPSIZE], *pPoints = NULL; |
| |
| jint *xpoints = (jint *) env->GetPrimitiveArrayCritical(xpointsarray, NULL); |
| if (xpoints != NULL) { |
| jint *ypoints = (jint *) env->GetPrimitiveArrayCritical(ypointsarray, NULL); |
| if (ypoints != NULL) { |
| pPoints = TransformPoly(xpoints, ypoints, transx, transy, |
| tmpPts, &npoints, FALSE, FALSE); |
| env->ReleasePrimitiveArrayCritical(ypointsarray, ypoints, JNI_ABORT); |
| } |
| env->ReleasePrimitiveArrayCritical(xpointsarray, xpoints, JNI_ABORT); |
| } |
| |
| if (pPoints == NULL) { |
| return; |
| } |
| |
| HDC hdc = wsdo->GetDC(env, wsdo, BRUSHONLY, NULL, clip, comp, color); |
| if (hdc == NULL) { |
| return; |
| } |
| ::SetPolyFillMode(hdc, ALTERNATE); |
| ::Polygon(hdc, pPoints, npoints); |
| wsdo->ReleaseDC(env, wsdo, hdc); |
| if (pPoints != tmpPts) { |
| free(pPoints); |
| } |
| } |
| |
| /* |
| * Class: sun_java2d_windows_GDIRenderer |
| * Method: doShape |
| * Signature: (Lsun/java2d/windows/GDIWindowSurfaceData;Lsun/java2d/pipe/Region; |
| * Ljava/awt/Composite;IIILjava/awt/geom/Path2D.Float;Z)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_java2d_windows_GDIRenderer_doShape |
| (JNIEnv *env, jobject wr, |
| jobject sData, |
| jobject clip, jobject comp, jint color, |
| jint transX, jint transY, |
| jobject p2df, jboolean isfill) |
| { |
| J2dTraceLn(J2D_TRACE_INFO, "GDIRenderer_doShape"); |
| J2dTraceLn4(J2D_TRACE_VERBOSE, |
| " color=0x%x transx=%-4d transy=%-4d isfill=%-4d", |
| color, transX, transY, isfill); |
| GDIWinSDOps *wsdo = GDIWindowSurfaceData_GetOps(env, sData); |
| if (wsdo == NULL) { |
| return; |
| } |
| |
| jarray typesarray = (jarray) env->GetObjectField(p2df, path2DTypesID); |
| jarray coordsarray = (jarray) env->GetObjectField(p2df, |
| path2DFloatCoordsID); |
| if (coordsarray == NULL) { |
| JNU_ThrowNullPointerException(env, "coordinates array"); |
| return; |
| } |
| jint numtypes = env->GetIntField(p2df, path2DNumTypesID); |
| if (env->GetArrayLength(typesarray) < numtypes) { |
| JNU_ThrowArrayIndexOutOfBoundsException(env, "types array"); |
| return; |
| } |
| jint maxcoords = env->GetArrayLength(coordsarray); |
| jint rule = env->GetIntField(p2df, path2DWindingRuleID); |
| |
| HDC hdc = wsdo->GetDC(env, wsdo, (isfill ? BRUSH : PEN), NULL, |
| clip, comp, color); |
| if (hdc == NULL) { |
| return; |
| } |
| |
| jbyte *types = (jbyte *) env->GetPrimitiveArrayCritical(typesarray, |
| NULL); |
| if (types == NULL) { |
| wsdo->ReleaseDC(env, wsdo, hdc); |
| return; |
| } |
| |
| jfloat *coords = (jfloat *) env->GetPrimitiveArrayCritical(coordsarray, |
| NULL); |
| if (coords == NULL) { |
| env->ReleasePrimitiveArrayCritical(typesarray, types, JNI_ABORT); |
| wsdo->ReleaseDC(env, wsdo, hdc); |
| return; |
| } |
| |
| ::SetPolyFillMode(hdc, (rule == java_awt_geom_PathIterator_WIND_NON_ZERO |
| ? WINDING : ALTERNATE)); |
| ::BeginPath(hdc); |
| |
| int index = 0; |
| BOOL ok = TRUE; |
| BOOL isempty = TRUE; |
| BOOL isapoint = TRUE; |
| int mx = 0, my = 0, x1 = 0, y1 = 0; |
| POINT ctrlpts[3]; |
| for (int i = 0; ok && i < numtypes; i++) { |
| switch (types[i]) { |
| case java_awt_geom_PathIterator_SEG_MOVETO: |
| if (!isfill && !isempty) { |
| // Fix for 4298688 - draw(Line) omits last pixel |
| // Windows omits the last pixel of a path when stroking. |
| // Fix up the last segment of the previous subpath by |
| // adding another segment after it that is only 1 pixel |
| // long. The first pixel of that segment will be drawn, |
| // but the second pixel is the one that Windows omits. |
| ::LineTo(hdc, x1+1, y1); |
| } |
| if (index + 2 <= maxcoords) { |
| mx = x1 = transX + (int) floor(coords[index++]); |
| my = y1 = transY + (int) floor(coords[index++]); |
| ::MoveToEx(hdc, x1, y1, NULL); |
| isempty = TRUE; |
| isapoint = TRUE; |
| } else { |
| ok = FALSE; |
| } |
| break; |
| case java_awt_geom_PathIterator_SEG_LINETO: |
| if (index + 2 <= maxcoords) { |
| x1 = transX + (int) floor(coords[index++]); |
| y1 = transY + (int) floor(coords[index++]); |
| ::LineTo(hdc, x1, y1); |
| isapoint = isapoint && (x1 == mx && y1 == my); |
| isempty = FALSE; |
| } else { |
| ok = FALSE; |
| } |
| break; |
| case java_awt_geom_PathIterator_SEG_QUADTO: |
| if (index + 4 <= maxcoords) { |
| ctrlpts[0].x = transX + (int) floor(coords[index++]); |
| ctrlpts[0].y = transY + (int) floor(coords[index++]); |
| ctrlpts[2].x = transX + (int) floor(coords[index++]); |
| ctrlpts[2].y = transY + (int) floor(coords[index++]); |
| ctrlpts[1].x = (ctrlpts[0].x * 2 + ctrlpts[2].x) / 3; |
| ctrlpts[1].y = (ctrlpts[0].y * 2 + ctrlpts[2].y) / 3; |
| ctrlpts[0].x = (ctrlpts[0].x * 2 + x1) / 3; |
| ctrlpts[0].y = (ctrlpts[0].y * 2 + y1) / 3; |
| x1 = ctrlpts[2].x; |
| y1 = ctrlpts[2].y; |
| ::PolyBezierTo(hdc, ctrlpts, 3); |
| isapoint = isapoint && (x1 == mx && y1 == my); |
| isempty = FALSE; |
| } else { |
| ok = FALSE; |
| } |
| break; |
| case java_awt_geom_PathIterator_SEG_CUBICTO: |
| if (index + 6 <= maxcoords) { |
| ctrlpts[0].x = transX + (int) floor(coords[index++]); |
| ctrlpts[0].y = transY + (int) floor(coords[index++]); |
| ctrlpts[1].x = transX + (int) floor(coords[index++]); |
| ctrlpts[1].y = transY + (int) floor(coords[index++]); |
| ctrlpts[2].x = transX + (int) floor(coords[index++]); |
| ctrlpts[2].y = transY + (int) floor(coords[index++]); |
| x1 = ctrlpts[2].x; |
| y1 = ctrlpts[2].y; |
| ::PolyBezierTo(hdc, ctrlpts, 3); |
| isapoint = isapoint && (x1 == mx && y1 == my); |
| isempty = FALSE; |
| } else { |
| ok = FALSE; |
| } |
| break; |
| case java_awt_geom_PathIterator_SEG_CLOSE: |
| ::CloseFigure(hdc); |
| if (x1 != mx || y1 != my) { |
| x1 = mx; |
| y1 = my; |
| ::MoveToEx(hdc, x1, y1, NULL); |
| isempty = TRUE; |
| isapoint = TRUE; |
| } else if (!isfill && !isempty && isapoint) { |
| ::LineTo(hdc, x1+1, y1); |
| ::MoveToEx(hdc, x1, y1, NULL); |
| isempty = TRUE; |
| isapoint = TRUE; |
| } |
| break; |
| } |
| } |
| env->ReleasePrimitiveArrayCritical(typesarray, types, JNI_ABORT); |
| env->ReleasePrimitiveArrayCritical(coordsarray, coords, JNI_ABORT); |
| if (ok) { |
| if (!isfill && !isempty) { |
| // Fix for 4298688 - draw(Line) omits last pixel |
| // Windows omits the last pixel of a path when stroking. |
| // Fix up the last segment of the previous subpath by |
| // adding another segment after it that is only 1 pixel |
| // long. The first pixel of that segment will be drawn, |
| // but the second pixel is the one that Windows omits. |
| ::LineTo(hdc, x1+1, y1); |
| } |
| ::EndPath(hdc); |
| if (isfill) { |
| ::FillPath(hdc); |
| } else { |
| ::StrokePath(hdc); |
| } |
| } else { |
| ::AbortPath(hdc); |
| JNU_ThrowArrayIndexOutOfBoundsException(env, "coords array"); |
| } |
| wsdo->ReleaseDC(env, wsdo, hdc); |
| } |
| |
| } /* extern "C" */ |
| |
| INLINE BOOL RectInMonitorRect(RECT *rCheck, RECT *rContainer) |
| { |
| // Assumption: left <= right, top <= bottom |
| if (rCheck->left >= rContainer->left && |
| rCheck->right <= rContainer->right && |
| rCheck->top >= rContainer->top && |
| rCheck->bottom <= rContainer->bottom) |
| { |
| return TRUE; |
| } else { |
| return FALSE; |
| } |
| } |
| |
| /* |
| * Class: sun_java2d_windows_GDIRenderer |
| * Method: devCopyArea |
| * Signature: (Lsun/java2d/windows/GDIWindowSurfaceData;IIIIII)V |
| */ |
| JNIEXPORT void JNICALL |
| Java_sun_java2d_windows_GDIRenderer_devCopyArea |
| (JNIEnv *env, jobject wr, |
| jobject wsd, |
| jint srcx, jint srcy, |
| jint dx, jint dy, |
| jint width, jint height) |
| { |
| GDIWinSDOps *wsdo = GDIWindowSurfaceData_GetOps(env, wsd); |
| J2dTraceLn(J2D_TRACE_INFO, "GDIWindowSurfaceData_devCopyArea"); |
| J2dTraceLn4(J2D_TRACE_VERBOSE, " srcx=%-4d srcy=%-4d dx=%-4d dy=%-4d", |
| srcx, srcy, dx, dy); |
| J2dTraceLn2(J2D_TRACE_VERBOSE, " w=%-4d h=%-4d", width, height); |
| if (wsdo == NULL) { |
| return; |
| } |
| if (wsdo->invalid) { |
| SurfaceData_ThrowInvalidPipeException(env, |
| "GDIRenderer_devCopyArea: invalid surface data"); |
| return; |
| } |
| |
| HDC hDC = wsdo->GetDC(env, wsdo, 0, NULL, NULL, NULL, 0); |
| if (hDC == NULL) { |
| return; |
| } |
| |
| RECT r; |
| ::SetRect(&r, srcx, srcy, srcx + width, srcy + height); |
| HRGN rgnUpdate = ::CreateRectRgn(0, 0, 0, 0); |
| VERIFY(::ScrollDC(hDC, dx, dy, &r, NULL, rgnUpdate, NULL)); |
| |
| // ScrollDC invalidates the part of the source rectangle that |
| // is outside of the destination rectangle on the assumption |
| // that you wanted to "move" the pixels from source to dest, |
| // and so now you will want to paint new pixels in the source. |
| // Since our copyarea operation involves no such semantics we |
| // are only interested in the part of the update region that |
| // corresponds to unavailable source pixels - i.e. the part |
| // that falls within the destination rectangle. |
| |
| // The update region will be in client relative coordinates |
| // but the destination rect will be in window relative coordinates |
| ::OffsetRect(&r, dx-wsdo->insets.left, dy-wsdo->insets.top); |
| HRGN rgnDst = ::CreateRectRgnIndirect(&r); |
| int result = ::CombineRgn(rgnUpdate, rgnUpdate, rgnDst, RGN_AND); |
| |
| // Invalidate the exposed area. |
| if (result != NULLREGION) { |
| ::InvalidateRgn(wsdo->window, rgnUpdate, TRUE); |
| } |
| ::DeleteObject(rgnUpdate); |
| ::DeleteObject(rgnDst); |
| |
| wsdo->ReleaseDC(env, wsdo, hDC); |
| } |