/* * 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: 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: 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; jint *xpoints = (jint *) env->GetPrimitiveArrayCritical(xpointsarray, NULL); jint *ypoints = (jint *) env->GetPrimitiveArrayCritical(ypointsarray, NULL); pPoints = TransformPoly(xpoints, ypoints, transx, transy, tmpPts, &npoints, FALSE, FALSE); env->ReleasePrimitiveArrayCritical(xpointsarray, xpoints, JNI_ABORT); env->ReleasePrimitiveArrayCritical(ypointsarray, ypoints, 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: 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); }
/* * 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: 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: 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: 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: 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; } ::SetPolyFillMode(hdc, (rule == java_awt_geom_PathIterator_WIND_NON_ZERO ? WINDING : ALTERNATE)); ::BeginPath(hdc); jbyte *types = (jbyte *) env->GetPrimitiveArrayCritical(typesarray, NULL); jfloat *coords = (jfloat *) env->GetPrimitiveArrayCritical(coordsarray, NULL); 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); }
/* * 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_GDIBlitLoops * Method: nativeBlit * Signature: (Lsun/java2d/SurfaceData;Lsun/java2d/SurfaceData;IIIIIIZ)V */ JNIEXPORT void JNICALL Java_sun_java2d_windows_GDIBlitLoops_nativeBlit (JNIEnv *env, jobject joSelf, jobject srcData, jobject dstData, jobject clip, jint srcx, jint srcy, jint dstx, jint dsty, jint width, jint height, jint rmask, jint gmask, jint bmask, jboolean needLut) { J2dTraceLn(J2D_TRACE_INFO, "GDIBlitLoops_nativeBlit"); SurfaceDataRasInfo srcInfo; SurfaceDataOps *srcOps = SurfaceData_GetOps(env, srcData); GDIWinSDOps *dstOps = GDIWindowSurfaceData_GetOps(env, dstData); jint lockFlags; HDC hDC = dstOps->GetDC(env, dstOps, 0, NULL, clip, NULL, 0); if (hDC == NULL) { return; } srcInfo.bounds.x1 = srcx; srcInfo.bounds.y1 = srcy; srcInfo.bounds.x2 = srcx + width; srcInfo.bounds.y2 = srcy + height; if (needLut) { lockFlags = (SD_LOCK_READ | SD_LOCK_LUT); } else { lockFlags = SD_LOCK_READ; } if (srcOps->Lock(env, srcOps, &srcInfo, lockFlags) != SD_SUCCESS) { dstOps->ReleaseDC(env, dstOps, hDC); return; } SurfaceDataBounds dstBounds = {dstx, dsty, dstx + width, dsty + height}; // Intersect the source and dest rects. Note that the source blit bounds // will be adjusted to the surfaces's bounds if needed. SurfaceData_IntersectBlitBounds(&(srcInfo.bounds), &dstBounds, dstx - srcx, dsty - srcy); srcx = srcInfo.bounds.x1; srcy = srcInfo.bounds.y1; dstx = dstBounds.x1; dsty = dstBounds.y1; width = srcInfo.bounds.x2 - srcInfo.bounds.x1; height = srcInfo.bounds.y2 - srcInfo.bounds.y1; if (width > 0 && height > 0) { BmiType bmi; // REMIND: A performance tweak here would be to make some of this // data static. For example, we could have one structure that is // always used for ByteGray copies and we only change dynamic data // in the structure with every new copy. Also, we could store // structures with Ops or with the Java objects so that surfaces // could retain their own DIB info and we would not need to // recreate it every time. srcOps->GetRasInfo(env, srcOps, &srcInfo); void *rasBase = ((char *)srcInfo.rasBase) + srcInfo.scanStride * srcy + srcInfo.pixelStride * srcx; // If scanlines are DWORD-aligned (scanStride is a multiple of 4), // then we can do the work much faster. This is due to a constraint // in the way DIBs are structured and parsed by GDI jboolean fastBlt = ((srcInfo.scanStride & 0x03) == 0); bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); bmi.bmiHeader.biWidth = srcInfo.scanStride/srcInfo.pixelStride; // fastBlt copies whole image in one call; else copy line-by-line bmi.bmiHeader.biHeight = (fastBlt) ? -(srcInfo.bounds.y2 - srcInfo.bounds.y1) : -1; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = srcInfo.pixelStride * 8; // 1,3,4 byte use BI_RGB, 2 byte use BI_BITFIELD... // 4 byte _can_ use BI_BITFIELD, but this seems to cause a performance // penalty. Since we only ever have one format (xrgb) for 32-bit // images that enter this function, just use BI_RGB. // Could do BI_RGB for 2-byte 555 format, but no perceived // performance benefit. bmi.bmiHeader.biCompression = (srcInfo.pixelStride != 2) ? BI_RGB : BI_BITFIELDS; bmi.bmiHeader.biSizeImage = (bmi.bmiHeader.biWidth * bmi.bmiHeader.biHeight * srcInfo.pixelStride); bmi.bmiHeader.biXPelsPerMeter = 0; bmi.bmiHeader.biYPelsPerMeter = 0; bmi.bmiHeader.biClrUsed = 0; bmi.bmiHeader.biClrImportant = 0; if (srcInfo.pixelStride == 1) { // Copy palette info into bitmap for 8-bit image if (needLut) { memcpy(bmi.colors.palette, srcInfo.lutBase, srcInfo.lutSize * sizeof(RGBQUAD)); if (srcInfo.lutSize != 256) { bmi.bmiHeader.biClrUsed = srcInfo.lutSize; } } else { // If no LUT needed, must be ByteGray src. If we have not // yet created the byteGrayPalette, create it now and copy // it into our temporary bmi structure. // REMIND: byteGrayPalette is a leak since we do not have // a mechansim to free it up. This should be fine, since it // is only 256 bytes for any process and only gets malloc'd // when using ByteGray surfaces. Eventually, we should use // the new Disposer mechanism to delete this native memory. if (byteGrayPalette == NULL) { byteGrayPalette = (RGBQUAD *)safe_Malloc(256 * sizeof(RGBQUAD)); for (int i = 0; i < 256; ++i) { byteGrayPalette[i].rgbRed = i; byteGrayPalette[i].rgbGreen = i; byteGrayPalette[i].rgbBlue = i; } } memcpy(bmi.colors.palette, byteGrayPalette, 256 * sizeof(RGBQUAD)); } } else if (srcInfo.pixelStride == 2) { // For 16-bit case, init the masks for the pixel depth bmi.colors.dwMasks[0] = rmask; bmi.colors.dwMasks[1] = gmask; bmi.colors.dwMasks[2] = bmask; } if (fastBlt) { // Window could go away at any time, leaving bits on the screen // from this GDI call, so make sure window still exists if (::IsWindowVisible(dstOps->window)) { // Could also call StretchDIBits. Testing showed slight // performance advantage of SetDIBits instead, so since we // have no need of scaling, might as well use SetDIBits. SetDIBitsToDevice(hDC, dstx, dsty, width, height, 0, 0, 0, height, rasBase, (BITMAPINFO*)&bmi, DIB_RGB_COLORS); } } else { // Source scanlines not DWORD-aligned - copy each scanline individually for (int i = 0; i < height; i += 1) { if (::IsWindowVisible(dstOps->window)) { SetDIBitsToDevice(hDC, dstx, dsty+i, width, 1, 0, 0, 0, 1, rasBase, (BITMAPINFO*)&bmi, DIB_RGB_COLORS); rasBase = (void*)((char*)rasBase + srcInfo.scanStride); } else { break; } } } SurfaceData_InvokeRelease(env, srcOps, &srcInfo); } SurfaceData_InvokeUnlock(env, srcOps, &srcInfo); dstOps->ReleaseDC(env, dstOps, hDC); return; }