From f19407dbe55c7a3ca5b8f231a3b8a2ea355e9a5b Mon Sep 17 00:00:00 2001 From: prrace Date: Fri, 24 Oct 2025 14:59:16 -0700 Subject: [PATCH 1/3] 8370637 --- .../classes/sun/awt/windows/WPrinterJob.java | 142 +++++++++--------- .../native/libawt/windows/awt_PrintJob.cpp | 128 +++++++++++++++- .../awt/PrintJob/PrintJobAfterEndTest.java | 104 +++++++++++++ .../jdk/java/awt/print/PrintAfterEndTest.java | 127 ++++++++++++++++ 4 files changed, 429 insertions(+), 72 deletions(-) create mode 100644 test/jdk/java/awt/PrintJob/PrintJobAfterEndTest.java create mode 100644 test/jdk/java/awt/print/PrintAfterEndTest.java diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java b/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java index 17d41036bcccd..01be858768529 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WPrinterJob.java @@ -929,35 +929,35 @@ protected int getNoncollatedCopies() { * Return the Window's device context that we are printing * into. */ - private long getPrintDC() { + private synchronized long getPrintDC() { return handleRecord.mPrintDC; } - private void setPrintDC(long mPrintDC) { + private synchronized void setPrintDC(long mPrintDC) { handleRecord.mPrintDC = mPrintDC; } - private long getDevMode() { + private synchronized long getDevMode() { return handleRecord.mPrintHDevMode; } - private void setDevMode(long mPrintHDevMode) { + private synchronized void setDevMode(long mPrintHDevMode) { handleRecord.mPrintHDevMode = mPrintHDevMode; } - private long getDevNames() { + private synchronized long getDevNames() { return handleRecord.mPrintHDevNames; } - private void setDevNames(long mPrintHDevNames) { + private synchronized void setDevNames(long mPrintHDevNames) { handleRecord.mPrintHDevNames = mPrintHDevNames; } - protected void beginPath() { + protected synchronized void beginPath() { beginPath(getPrintDC()); } - protected void endPath() { + protected synchronized void endPath() { endPath(getPrintDC()); } @@ -972,23 +972,23 @@ protected void restoreTransform() { setGraphicsMode(graphicsMode); } - protected void closeFigure() { + protected synchronized void closeFigure() { closeFigure(getPrintDC()); } - protected void fillPath() { + protected synchronized void fillPath() { fillPath(getPrintDC()); } - protected void moveTo(float x, float y) { + protected synchronized void moveTo(float x, float y) { moveTo(getPrintDC(), x, y); } - protected void lineTo(float x, float y) { + protected synchronized void lineTo(float x, float y) { lineTo(getPrintDC(), x, y); } - protected void polyBezierTo(float control1x, float control1y, + protected synchronized void polyBezierTo(float control1x, float control1y, float control2x, float control2y, float endX, float endY) { @@ -1003,14 +1003,14 @@ protected void polyBezierTo(float control1x, float control1y, * be one of the following Windows constants: * {@code ALTERNATE} or {@code WINDING}. */ - protected void setPolyFillMode(int fillRule) { + protected synchronized void setPolyFillMode(int fillRule) { setPolyFillMode(getPrintDC(), fillRule); } /** * Set the GDI graphics mode to {@code GM_ADVANCED}. */ - private int setAdvancedGraphicsMode() { + private synchronized int setAdvancedGraphicsMode() { return setAdvancedGraphicsMode(getPrintDC()); } @@ -1020,28 +1020,28 @@ private int setAdvancedGraphicsMode() { * be one of the following Windows constants: * {@code GM_COMPATIBLE} or {@code GM_ADVANCED}. */ - private void setGraphicsMode(int mode) { + private synchronized void setGraphicsMode(int mode) { setGraphicsMode(getPrintDC(), mode); } /** * Scale the GDI World Transform. */ - private void scale(double scaleX, double scaleY) { + private synchronized void scale(double scaleX, double scaleY) { scale(getPrintDC(), scaleX, scaleY); } /** * Get the GDI World Transform. */ - private void getWorldTransform(double[] transform) { + private synchronized void getWorldTransform(double[] transform) { getWorldTransform(getPrintDC(), transform); } /** * Set the GDI World Transform. */ - private void setWorldTransform(double[] transform) { + private synchronized void setWorldTransform(double[] transform) { setWorldTransform(getPrintDC(), transform); } @@ -1051,7 +1051,7 @@ private void setWorldTransform(double[] transform) { * is created, select it in the current printing device * context and free the old brush. */ - protected void selectSolidBrush(Color color) { + protected synchronized void selectSolidBrush(Color color) { /* We only need to select a brush if the color has changed. */ @@ -1070,7 +1070,7 @@ protected void selectSolidBrush(Color color) { * Return the x coordinate of the current pen * position in the print device context. */ - protected int getPenX() { + protected synchronized int getPenX() { return getPenX(getPrintDC()); } @@ -1080,7 +1080,7 @@ protected int getPenX() { * Return the y coordinate of the current pen * position in the print device context. */ - protected int getPenY() { + protected synchronized int getPenY() { return getPenY(getPrintDC()); } @@ -1089,16 +1089,16 @@ protected int getPenY() { * Set the current path in the printer device's * context to be clipping path. */ - protected void selectClipPath() { + protected synchronized void selectClipPath() { selectClipPath(getPrintDC()); } - protected void frameRect(float x, float y, float width, float height) { + protected synchronized void frameRect(float x, float y, float width, float height) { frameRect(getPrintDC(), x, y, width, height); } - protected void fillRect(float x, float y, float width, float height, + protected synchronized void fillRect(float x, float y, float width, float height, Color color) { float[] rgb = color.getRGBColorComponents(null); @@ -1109,7 +1109,7 @@ protected void fillRect(float x, float y, float width, float height, } - protected void selectPen(float width, Color color) { + protected synchronized void selectPen(float width, Color color) { float[] rgb = color.getRGBColorComponents(null); @@ -1120,7 +1120,7 @@ protected void selectPen(float width, Color color) { } - protected boolean selectStylePen(int cap, int join, float width, + protected synchronized boolean selectStylePen(int cap, int join, float width, Color color) { long endCap; @@ -1152,7 +1152,7 @@ protected boolean selectStylePen(int cap, int join, float width, * Set a GDI font capable of drawing the java Font * passed in. */ - protected boolean setFont(String family, float size, int style, + protected synchronized boolean setFont(String family, float size, int style, int rotation, float awScale) { if (family.isEmpty()) { @@ -1187,7 +1187,7 @@ protected boolean setFont(String family, float size, int style, /** * Set the GDI color for text drawing. */ - protected void setTextColor(Color color) { + protected synchronized void setTextColor(Color color) { /* We only need to select a brush if the color has changed. */ @@ -1206,7 +1206,7 @@ protected void setTextColor(Color color) { * Draw the string {@code text} to the printer's * device context at the specified position. */ - protected void textOut(String str, float x, float y, + protected synchronized void textOut(String str, float x, float y, float[] positions) { /* Don't leave handling of control chars to GDI. * If control chars are removed, 'positions' isn't valid. @@ -1226,7 +1226,7 @@ protected void textOut(String str, float x, float y, * Draw the glyphs {@code glyphs} to the printer's * device context at the specified position. */ - protected void glyphsOut(int []glyphs, float x, float y, + protected synchronized void glyphsOut(int []glyphs, float x, float y, float[] positions) { /* TrueType glyph codes are 16 bit values, so can be packed @@ -1254,7 +1254,7 @@ protected void glyphsOut(int []glyphs, float x, float y, * rendering so also remove them for measurement so that * this measurement can be properly compared with JDK measurement. */ - protected int getGDIAdvance(String text) { + protected synchronized int getGDIAdvance(String text) { /* Don't leave handling of control chars to GDI. */ text = removeControlChars(text); if (text.length() == 0) { @@ -1275,7 +1275,7 @@ protected int getGDIAdvance(String text) { * by {@code srcX}, {@code srcY}, * {@code srcWidth}, and srcHeight. */ - protected void drawImage3ByteBGR(byte[] image, + protected synchronized void drawImage3ByteBGR(byte[] image, float destX, float destY, float destWidth, float destHeight, float srcX, float srcY, @@ -1306,7 +1306,7 @@ protected void drawImage3ByteBGR(byte[] image, * There's no alignment problem as GDI expects this to be packed * and each struct will start on a 4 byte boundary anyway. */ - protected void drawDIBImage(byte[] image, + protected synchronized void drawDIBImage(byte[] image, float destX, float destY, float destWidth, float destHeight, float srcX, float srcY, @@ -1338,7 +1338,7 @@ protected void drawDIBImage(byte[] image, * Begin a new page. */ @Override - protected void startPage(PageFormat format, Printable painter, + protected synchronized void startPage(PageFormat format, Printable painter, int index, boolean paperChanged) { /* Invalidate any device state caches we are @@ -1355,7 +1355,7 @@ protected void startPage(PageFormat format, Printable painter, * End a page. */ @Override - protected void endPage(PageFormat format, Printable painter, + protected synchronized void endPage(PageFormat format, Printable painter, int index) { deviceEndPage(format, painter, index); @@ -1402,7 +1402,7 @@ public void setCopies(int copies) { * is reflected back up to Java code */ @Override - protected native void initPrinter(); + protected synchronized native void initPrinter(); /** * Call Window's StartDoc routine to begin a @@ -1415,10 +1415,10 @@ public void setCopies(int copies) { * user may cancel out of it. Note that the implementation of * cancel() throws PrinterAbortException to indicate the user cancelled. */ - private native boolean _startDoc(String dest, String jobName) + private synchronized native boolean _startDoc(String dest, String jobName) throws PrinterException; @Override - protected void startDoc() throws PrinterException { + protected synchronized void startDoc() throws PrinterException { if (!_startDoc(mDestination, getJobName())) { cancel(); } @@ -1429,31 +1429,31 @@ protected void startDoc() throws PrinterException { * print job. */ @Override - protected native void endDoc(); + protected synchronized native void endDoc(); /** * Call Window's AbortDoc routine to abort a * print job. */ @Override - protected native void abortDoc(); + protected synchronized native void abortDoc(); /** * Call Windows native resource freeing APIs */ - private static native void deleteDC(long dc, long devmode, long devnames); + private static synchronized native void deleteDC(long dc, long devmode, long devnames); /** * Begin a new page. This call's Window's * StartPage routine. */ - protected native void deviceStartPage(PageFormat format, Printable painter, + protected synchronized native void deviceStartPage(PageFormat format, Printable painter, int index, boolean paperChanged); /** * End a page. This call's Window's EndPage * routine. */ - protected native void deviceEndPage(PageFormat format, Printable painter, + protected synchronized native void deviceEndPage(PageFormat format, Printable painter, int index); /** @@ -1464,46 +1464,46 @@ protected native void deviceEndPage(PageFormat format, Printable painter, * specified by the caller. */ @Override - protected native void printBand(byte[] data, int x, int y, + protected synchronized native void printBand(byte[] data, int x, int y, int width, int height); /** * Begin a Window's rendering path in the device * context {@code printDC}. */ - protected native void beginPath(long printDC); + protected synchronized native void beginPath(long printDC); /** * End a Window's rendering path in the device * context {@code printDC}. */ - protected native void endPath(long printDC); + protected synchronized native void endPath(long printDC); /** * Close a subpath in a Window's rendering path in the device * context {@code printDC}. */ - protected native void closeFigure(long printDC); + protected synchronized native void closeFigure(long printDC); /** * Fill a defined Window's rendering path in the device * context {@code printDC}. */ - protected native void fillPath(long printDC); + protected synchronized native void fillPath(long printDC); /** * Move the Window's pen position to {@code (x,y)} * in the device context {@code printDC}. */ - protected native void moveTo(long printDC, float x, float y); + protected synchronized native void moveTo(long printDC, float x, float y); /** * Draw a line from the current pen position to * {@code (x,y)} in the device context {@code printDC}. */ - protected native void lineTo(long printDC, float x, float y); + protected synchronized native void lineTo(long printDC, float x, float y); - protected native void polyBezierTo(long printDC, + protected synchronized native void polyBezierTo(long printDC, float control1x, float control1y, float control2x, float control2y, float endX, float endY); @@ -1514,13 +1514,13 @@ protected native void polyBezierTo(long printDC, * be one of the following Windows constants: * {@code ALTERNATE} or {@code WINDING}. */ - protected native void setPolyFillMode(long printDC, int fillRule); + protected synchronized native void setPolyFillMode(long printDC, int fillRule); /** * Set the GDI graphics mode to {@code GM_ADVANCED} * into the device context {@code printDC}. */ - protected native int setAdvancedGraphicsMode(long printDC); + protected synchronized native int setAdvancedGraphicsMode(long printDC); /** * Set the GDI graphics {@code mode} @@ -1529,25 +1529,25 @@ protected native void polyBezierTo(long printDC, * be one of the following Windows constants: * {@code GM_COMPATIBLE} or {@code GM_ADVANCED}. */ - protected native void setGraphicsMode(long printDC, int mode); + protected synchronized native void setGraphicsMode(long printDC, int mode); /** * Scale the GDI World Transform * of the device context {@code printDC}. */ - protected native void scale(long printDC, double scaleX, double scaleY); + protected synchronized native void scale(long printDC, double scaleX, double scaleY); /** * Get the GDI World Transform * from the device context {@code printDC}. */ - protected native void getWorldTransform(long printDC, double[] transform); + protected synchronized native void getWorldTransform(long printDC, double[] transform); /** * Set the GDI World Transform * into the device context {@code printDC}. */ - protected native void setWorldTransform(long printDC, double[] transform); + protected synchronized native void setWorldTransform(long printDC, double[] transform); /** * Create a Window's solid brush for the color specified @@ -1555,7 +1555,7 @@ protected native void polyBezierTo(long printDC, * is created, select it in the device * context {@code printDC} and free the old brush. */ - protected native void selectSolidBrush(long printDC, + protected synchronized native void selectSolidBrush(long printDC, int red, int green, int blue); /** @@ -1563,32 +1563,32 @@ protected native void selectSolidBrush(long printDC, * position in the device context * {@code printDC}. */ - protected native int getPenX(long printDC); + protected synchronized native int getPenX(long printDC); /** * Return the y coordinate of the current pen * position in the device context * {@code printDC}. */ - protected native int getPenY(long printDC); + protected synchronized native int getPenY(long printDC); /** * Select the device context's current path * to be the clipping path. */ - protected native void selectClipPath(long printDC); + protected synchronized native void selectClipPath(long printDC); /** * Draw a rectangle using specified brush. */ - protected native void frameRect(long printDC, float x, float y, + protected synchronized native void frameRect(long printDC, float x, float y, float width, float height); /** * Fill a rectangle specified by the coordinates using * specified brush. */ - protected native void fillRect(long printDC, float x, float y, + protected synchronized native void fillRect(long printDC, float x, float y, float width, float height, int red, int green, int blue); @@ -1596,14 +1596,14 @@ protected native void fillRect(long printDC, float x, float y, * Create a solid brush using the RG & B colors and width. * Select this brush and delete the old one. */ - protected native void selectPen(long printDC, float width, + protected synchronized native void selectPen(long printDC, float width, int red, int green, int blue); /** * Create a solid brush using the RG & B colors and specified * pen styles. Select this created brush and delete the old one. */ - protected native boolean selectStylePen(long printDC, long cap, + protected synchronized native boolean selectStylePen(long printDC, long cap, long join, float width, int red, int green, int blue); @@ -1611,7 +1611,7 @@ protected native boolean selectStylePen(long printDC, long cap, * Set a GDI font capable of drawing the java Font * passed in. */ - protected native boolean setFont(long printDC, String familyName, + protected synchronized native boolean setFont(long printDC, String familyName, float fontSize, boolean bold, boolean italic, @@ -1622,7 +1622,7 @@ protected native boolean setFont(long printDC, String familyName, /** * Set the GDI color for text drawing. */ - protected native void setTextColor(long printDC, + protected synchronized native void setTextColor(long printDC, int red, int green, int blue); @@ -1631,12 +1631,12 @@ protected native void setTextColor(long printDC, * context {@code printDC} at the specified * position. */ - protected native void textOut(long printDC, String text, + protected synchronized native void textOut(long printDC, String text, int strlen, boolean glyphs, float x, float y, float[] positions); - private native int getGDIAdvance(long printDC, String text); + private synchronized native int getGDIAdvance(long printDC, String text); /** * Draw the DIB compatible image buffer represented by @@ -1653,7 +1653,7 @@ protected native void textOut(long printDC, String text, * At the very least it needs to be padded so each scanline is * DWORD aligned. Also we "flip" the image to make it a bottom-up DIB. */ - private native void drawDIBImage(long printDC, byte[] image, + private synchronized native void drawDIBImage(long printDC, byte[] image, float destX, float destY, float destWidth, float destHeight, float srcX, float srcY, diff --git a/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp b/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp index 9abe32e0fcc37..b186c176c4d00 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp @@ -1523,6 +1523,7 @@ Java_sun_awt_windows_WPrinterJob_endDoc(JNIEnv *env, jobject self) { if (printDC != NULL){ SAVE_CONTROLWORD ::EndDoc(printDC); + AwtPrintControl::setPrintDC(env, self, (HDC)NULL); RESTORE_CONTROLWORD } @@ -1583,7 +1584,9 @@ Java_sun_awt_windows_WPrinterJob_deleteDC TRY_NO_VERIFY; - DeletePrintDC((HDC)dc); + if ((HDC)dc != NULL) { + DeletePrintDC((HDC)dc); + } if ((HGLOBAL)devmode != NULL){ ::GlobalFree((HGLOBAL)devmode); @@ -1850,6 +1853,9 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_printBand jint width, jint height) { HDC printDC = AwtPrintControl::getPrintDC(env, self); + if ((HDC)printDC == NULL) { + return; + } doPrintBand(env, printDC, imageArray, x, y, width, height); } @@ -1862,6 +1868,10 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_beginPath (JNIEnv *env , jobject self, jlong printDC) { TRY; + if ((HDC)printDC == NULL) { + return; + } + (void) ::BeginPath((HDC)printDC); CATCH_BAD_ALLOC; @@ -1876,6 +1886,10 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_endPath (JNIEnv *env, jobject self, jlong printDC) { TRY; + if ((HDC)printDC == NULL) { + return; + } + (void) ::EndPath((HDC)printDC); CATCH_BAD_ALLOC; @@ -1890,6 +1904,10 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_fillPath (JNIEnv *env, jobject self, jlong printDC) { TRY; + if ((HDC)printDC == NULL) { + return; + } + (void) ::FillPath((HDC)printDC); CATCH_BAD_ALLOC; @@ -1904,6 +1922,10 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_closeFigure (JNIEnv *env, jobject self, jlong printDC) { TRY; + if ((HDC)printDC == NULL) { + return; + } + (void) ::CloseFigure((HDC)printDC); CATCH_BAD_ALLOC; @@ -1918,6 +1940,10 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_lineTo (JNIEnv *env, jobject self, jlong printDC, jfloat x, jfloat y) { TRY; + if ((HDC)printDC == NULL) { + return; + } + (void) ::LineTo((HDC)printDC, ROUND_TO_LONG(x), ROUND_TO_LONG(y)); CATCH_BAD_ALLOC; @@ -1933,6 +1959,10 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_moveTo (JNIEnv *env, jobject self, jlong printDC, jfloat x, jfloat y) { TRY; + if ((HDC)printDC == NULL) { + return; + } + (void) ::MoveToEx((HDC)printDC, ROUND_TO_LONG(x), ROUND_TO_LONG(y), NULL); CATCH_BAD_ALLOC; @@ -1951,6 +1981,10 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_polyBezierTo TRY; + if ((HDC)printDC == NULL) { + return; + } + POINT points[3]; points[0].x = ROUND_TO_LONG(control1x); @@ -1974,6 +2008,10 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_setPolyFillMode (JNIEnv *env, jobject self, jlong printDC, jint fillRule) { TRY; + if ((HDC)printDC == NULL) { + return; + } + (void) ::SetPolyFillMode((HDC)printDC, fillRule); CATCH_BAD_ALLOC; @@ -1988,6 +2026,10 @@ JNIEXPORT jint JNICALL Java_sun_awt_windows_WPrinterJob_setAdvancedGraphicsMode (JNIEnv *env, jobject self, jlong printDC) { TRY; + if ((HDC)printDC == NULL) { + return 0; + } + int oldGraphicsMode = ::SetGraphicsMode((HDC)printDC, GM_ADVANCED); DASSERT(oldGraphicsMode != 0); return (jint) oldGraphicsMode; @@ -2004,6 +2046,10 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_setGraphicsMode (JNIEnv *env, jobject self, jlong printDC, jint mode) { TRY; + if ((HDC)printDC == NULL) { + return; + } + int oldGraphicsMode = ::SetGraphicsMode((HDC)printDC, mode); DASSERT(oldGraphicsMode != 0); @@ -2019,6 +2065,10 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_scale (JNIEnv *env, jobject self, jlong printDC, jdouble scaleX, jdouble scaleY) { TRY; + if ((HDC)printDC == NULL) { + return; + } + XFORM xForm; xForm.eM11 = (FLOAT) scaleX; @@ -2043,6 +2093,10 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_getWorldTransform (JNIEnv* env, jobject self, jlong printDC, jdoubleArray transform) { TRY; + if ((HDC)printDC == NULL) { + return; + } + double elems[6]; XFORM xForm; @@ -2070,6 +2124,10 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_setWorldTransform (JNIEnv* env, jobject self, jlong printDC, jdoubleArray transform) { TRY; + if ((HDC)printDC == NULL) { + return; + } + double *elems; XFORM xForm; @@ -2100,6 +2158,10 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_selectSolidBrush TRY; + if ((HDC)printDC == NULL) { + return; + } + HBRUSH colorBrush = ::CreateSolidBrush(RGB(red, green, blue)); HBRUSH oldBrush = (HBRUSH)::SelectObject((HDC)printDC, colorBrush); DeleteObject(oldBrush); @@ -2117,6 +2179,10 @@ JNIEXPORT jint JNICALL Java_sun_awt_windows_WPrinterJob_getPenX TRY; + if ((HDC)printDC == NULL) { + return 0; + } + POINT where; ::GetCurrentPositionEx((HDC)printDC, &where); @@ -2135,6 +2201,10 @@ JNIEXPORT jint JNICALL Java_sun_awt_windows_WPrinterJob_getPenY TRY; + if ((HDC)printDC == NULL) { + return 0; + } + POINT where; ::GetCurrentPositionEx((HDC)printDC, &where); @@ -2153,6 +2223,10 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_selectClipPath TRY; + if ((HDC)printDC == NULL) { + return; + } + ::SelectClipPath((HDC)printDC, RGN_COPY); CATCH_BAD_ALLOC; @@ -2170,6 +2244,10 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_frameRect TRY; + if ((HDC)printDC == NULL) { + return; + } + POINT points[5]; points[0].x = ROUND_TO_LONG(x); @@ -2200,6 +2278,10 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_fillRect TRY; + if ((HDC)printDC == NULL) { + return; + } + RECT rect; rect.left = ROUND_TO_LONG(x); rect.top = ROUND_TO_LONG(y); @@ -2228,6 +2310,10 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_selectPen TRY; + if ((HDC)printDC == NULL) { + return; + } + HPEN hpen = ::CreatePen(PS_SOLID, ROUND_TO_LONG(width), RGB(red, green, blue)); @@ -2254,6 +2340,10 @@ JNIEXPORT jboolean JNICALL Java_sun_awt_windows_WPrinterJob_selectStylePen TRY; + if ((HDC)printDC == NULL) { + return JNI_FALSE; + } + LOGBRUSH logBrush; logBrush.lbStyle = PS_SOLID ; @@ -2287,6 +2377,10 @@ JNIEXPORT jboolean JNICALL Java_sun_awt_windows_WPrinterJob_setFont jfloat fontSize, jboolean isBold, jboolean isItalic, jint rotation, jfloat awScale) { + if ((HDC)printDC == NULL) { + return JNI_FALSE; + } + jboolean didSetFont = JNI_FALSE; didSetFont = jFontToWFontW(env, (HDC)printDC, @@ -2317,6 +2411,10 @@ static jboolean jFontToWFontW(JNIEnv *env, HDC printDC, jstring fontName, LOGFONTW matchedLogFont; BOOL foundFont = false; // Assume we didn't find a matching GDI font. + if ((HDC)printDC == NULL) { + return JNI_FALSE; + } + memset(&matchedLogFont, 0, sizeof(matchedLogFont)); LPCWSTR fontNameW = JNU_GetStringPlatformChars(env, fontName, NULL); @@ -2478,6 +2576,10 @@ static int embolden(int currentWeight) JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_setTextColor (JNIEnv *env, jobject self, jlong printDC, jint red, jint green, jint blue) { + if ((HDC)printDC == NULL) { + return; + } + (void) ::SetTextColor( (HDC)printDC, RGB(red, green, blue)); } @@ -2485,6 +2587,11 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_setTextColor JNIEXPORT jint JNICALL Java_sun_awt_windows_WPrinterJob_getGDIAdvance (JNIEnv *env, jobject self, jlong printDC, jstring text) { + + if ((HDC)printDC == NULL) { + return 0; + } + SIZE size; LPCWSTR wText = JNU_GetStringPlatformChars(env, text, NULL); CHECK_NULL_RETURN(wText, 0); @@ -2538,6 +2645,9 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_textOut (JNIEnv *env, jobject self, jlong printDC, jstring text, jint strLen, jboolean glyphCodes, jfloat x, jfloat y, jfloatArray positions) { + if ((HDC)printDC == NULL) { + return; + } long posX = ROUND_TO_LONG(x); long posY = ROUND_TO_LONG(y); @@ -2832,6 +2942,10 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_drawDIBImage jfloat srcWidth, jfloat srcHeight, jint bitCount, jbyteArray bmiColorsArray) { + if ((HDC)printDC == NULL) { + return; + } + int result = 0; assert(printDC != NULL); @@ -2922,6 +3036,10 @@ static void doPrintBand(JNIEnv *env, HDC printDC, jbyteArray imageArray, TRY; + if ((HDC)printDC == NULL) { + return; + } + jbyte *image = NULL; try { long scanLineStride = J2DRasterBPP * width; @@ -2966,6 +3084,10 @@ static int bitsToDevice(HDC printDC, jbyte *image, long destX, long destY, long width, long height) { int result = 0; + if ((HDC)printDC == NULL) { + return result; + } + assert(printDC != NULL); assert(image != NULL); assert(destX >= 0); @@ -3707,6 +3829,10 @@ static double convertToPoints(long value, int units) { */ void setCapabilities(JNIEnv *env, jobject self, HDC printDC) { + if ((HDC)printDC == NULL) { + return; + } + jboolean err; // width of page in pixels jint pageWid = GetDeviceCaps(printDC, PHYSICALWIDTH); diff --git a/test/jdk/java/awt/PrintJob/PrintJobAfterEndTest.java b/test/jdk/java/awt/PrintJob/PrintJobAfterEndTest.java new file mode 100644 index 0000000000000..caa2d1bb325b1 --- /dev/null +++ b/test/jdk/java/awt/PrintJob/PrintJobAfterEndTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2025, 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. + * + * 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. + */ + + +/* + @test + @bug 8370141 8370637 + @summary Test no crash printing to Graphics after job is ended. + @key headful printer + @run main PrintJobAfterEndTest +*/ + +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.JobAttributes; +import java.awt.JobAttributes.DialogType; +import java.awt.JobAttributes.DestinationType; +import java.awt.PageAttributes; +import java.awt.PrintJob; +import java.awt.Toolkit; +import java.util.concurrent.CountDownLatch; + +public class PrintJobAfterEndTest { + + public static void main(String[] args) throws Exception { + + JobAttributes jobAttributes = new JobAttributes(); + jobAttributes.setDialog(DialogType.NONE); + jobAttributes.setDestination(DestinationType.FILE); + jobAttributes.setFileName("out.prn"); + + PageAttributes pageAttributes = new PageAttributes(); + + Frame f = new Frame(); + Toolkit tk = f.getToolkit(); + + for (int i = 0; i < 500; i++) { + PrintJob job = tk.getPrintJob(f, "Print Crash Test", jobAttributes, pageAttributes); + if (job != null) { + Graphics g = job.getGraphics(); + CountDownLatch latch = new CountDownLatch(1); + + Thread endThread = new Thread(() -> { + try { + latch.await(); + job.end(); + } catch (Throwable t) { + t.printStackTrace(); + } + }); + + Thread drawThread = new Thread(() -> { + try { + latch.await(); + g.clearRect(10, 10, 100, 100); + g.drawRect(0, 300, 200, 400); + g.fillRect(0, 300, 200, 400); + g.drawLine(0, 100, 200, 100); + g.drawString("Hello", 200, 200); + g.drawOval(200, 200, 200, 200); + int[] pts = new int[] { 10, 200, 100 }; + g.drawPolyline(pts, pts, pts.length); + g.drawPolygon(pts, pts, pts.length); + g.fillPolygon(pts, pts, pts.length); + } catch (Throwable t) { + t.printStackTrace(); + } + }); + + if ( i % 2 == 0) { + drawThread.start(); + endThread.start(); + } else { + endThread.start(); + drawThread.start(); + } + latch.countDown(); + + endThread.join(); + drawThread.join(); + } + } + } +} diff --git a/test/jdk/java/awt/print/PrintAfterEndTest.java b/test/jdk/java/awt/print/PrintAfterEndTest.java new file mode 100644 index 0000000000000..1825276223e2f --- /dev/null +++ b/test/jdk/java/awt/print/PrintAfterEndTest.java @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2025, 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. + * + * 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. + */ + +/** + * @test + * @key printer + * @bug 8370141 8370637 + * @summary No crash when printing after job completed. + * @run main PrintAfterEndTest + */ + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.print.Pageable; +import java.awt.print.PageFormat; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.standard.Destination; +import java.io.File; +import java.util.concurrent.CountDownLatch; + +public class PrintAfterEndTest implements Printable { + + volatile Graphics peekgraphics; + volatile Graphics pathgraphics; + + public static void main(String args[]) throws Exception { + + for (int i = 0; i < 500; i++) { + PrintAfterEndTest paet = new PrintAfterEndTest(); + paet.print(); + } + } + + void print() throws Exception { + PrinterJob pjob = PrinterJob.getPrinterJob(); + if (pjob == null || pjob.getPrintService() == null) { + System.out.println("Unable to create a PrintJob"); + return; + } + + CountDownLatch latch = new CountDownLatch(1); + HashPrintRequestAttributeSet aset = new HashPrintRequestAttributeSet(); + File file = new File("out.prn"); + Destination destination = new Destination(file.toURI()); + aset.add(destination); + pjob.setPrintable(this); + pjob.print(aset); + + DrawRunnable tpeek = new DrawRunnable(peekgraphics, latch); + DrawRunnable tpath = new DrawRunnable(pathgraphics, latch); + tpeek.start(); + tpath.start(); + latch.countDown(); + tpeek.join(); + tpath.join(); + } + + static class DrawRunnable extends Thread { + + Graphics g; + CountDownLatch latch; + DrawRunnable(Graphics g, CountDownLatch latch) { + this.g = g; + this.latch = latch; + } + + public void run() { + if (g == null) { + return; + } + try { + latch.await(); + g.clearRect(10, 10, 100, 100); + g.drawRect(0, 300, 200, 400); + g.fillRect(0, 300, 200, 400); + g.drawLine(0, 100, 200, 100); + g.drawString("Hello", 200, 200); + g.drawOval(200, 200, 200, 200); + int[] pts = new int[] { 10, 200, 100 }; + g.drawPolyline(pts, pts, pts.length); + g.drawPolygon(pts, pts, pts.length); + g.fillPolygon(pts, pts, pts.length); + g.dispose(); + } catch (Throwable t) { + } + } + } + + public int print(Graphics g, PageFormat pf, int pageIndex) { + if (pageIndex > 0) { + return NO_SUCH_PAGE; + } + if (peekgraphics == null) { + peekgraphics = g.create(); + } else if (pathgraphics == null) { + pathgraphics = g.create(); + } + Graphics2D g2d = (Graphics2D)g; + g2d.translate(pf.getImageableX(), pf.getImageableY()); + g.drawString("random string", 100,20); + return PAGE_EXISTS; + } + +} From f42de75d347a5b020fd3b3557f729c1f42ad84e8 Mon Sep 17 00:00:00 2001 From: prrace Date: Thu, 30 Oct 2025 14:11:32 -0700 Subject: [PATCH 2/3] 8370637 --- test/jdk/java/awt/print/PrinterJob/PrintAfterEndTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/java/awt/print/PrinterJob/PrintAfterEndTest.java b/test/jdk/java/awt/print/PrinterJob/PrintAfterEndTest.java index a1d173681e7fb..1825276223e2f 100644 --- a/test/jdk/java/awt/print/PrinterJob/PrintAfterEndTest.java +++ b/test/jdk/java/awt/print/PrinterJob/PrintAfterEndTest.java @@ -24,7 +24,7 @@ /** * @test * @key printer - * @bug 8370141 + * @bug 8370141 8370637 * @summary No crash when printing after job completed. * @run main PrintAfterEndTest */ From 4a4db71b7d90674faeb284d8571d422414d395cc Mon Sep 17 00:00:00 2001 From: prrace Date: Thu, 30 Oct 2025 14:13:31 -0700 Subject: [PATCH 3/3] 8370637 --- .../jdk/java/awt/print/PrintAfterEndTest.java | 127 ------------------ 1 file changed, 127 deletions(-) delete mode 100644 test/jdk/java/awt/print/PrintAfterEndTest.java diff --git a/test/jdk/java/awt/print/PrintAfterEndTest.java b/test/jdk/java/awt/print/PrintAfterEndTest.java deleted file mode 100644 index 1825276223e2f..0000000000000 --- a/test/jdk/java/awt/print/PrintAfterEndTest.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2025, 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. - * - * 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. - */ - -/** - * @test - * @key printer - * @bug 8370141 8370637 - * @summary No crash when printing after job completed. - * @run main PrintAfterEndTest - */ - -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.print.Pageable; -import java.awt.print.PageFormat; -import java.awt.print.Printable; -import java.awt.print.PrinterException; -import java.awt.print.PrinterJob; -import javax.print.attribute.HashPrintRequestAttributeSet; -import javax.print.attribute.standard.Destination; -import java.io.File; -import java.util.concurrent.CountDownLatch; - -public class PrintAfterEndTest implements Printable { - - volatile Graphics peekgraphics; - volatile Graphics pathgraphics; - - public static void main(String args[]) throws Exception { - - for (int i = 0; i < 500; i++) { - PrintAfterEndTest paet = new PrintAfterEndTest(); - paet.print(); - } - } - - void print() throws Exception { - PrinterJob pjob = PrinterJob.getPrinterJob(); - if (pjob == null || pjob.getPrintService() == null) { - System.out.println("Unable to create a PrintJob"); - return; - } - - CountDownLatch latch = new CountDownLatch(1); - HashPrintRequestAttributeSet aset = new HashPrintRequestAttributeSet(); - File file = new File("out.prn"); - Destination destination = new Destination(file.toURI()); - aset.add(destination); - pjob.setPrintable(this); - pjob.print(aset); - - DrawRunnable tpeek = new DrawRunnable(peekgraphics, latch); - DrawRunnable tpath = new DrawRunnable(pathgraphics, latch); - tpeek.start(); - tpath.start(); - latch.countDown(); - tpeek.join(); - tpath.join(); - } - - static class DrawRunnable extends Thread { - - Graphics g; - CountDownLatch latch; - DrawRunnable(Graphics g, CountDownLatch latch) { - this.g = g; - this.latch = latch; - } - - public void run() { - if (g == null) { - return; - } - try { - latch.await(); - g.clearRect(10, 10, 100, 100); - g.drawRect(0, 300, 200, 400); - g.fillRect(0, 300, 200, 400); - g.drawLine(0, 100, 200, 100); - g.drawString("Hello", 200, 200); - g.drawOval(200, 200, 200, 200); - int[] pts = new int[] { 10, 200, 100 }; - g.drawPolyline(pts, pts, pts.length); - g.drawPolygon(pts, pts, pts.length); - g.fillPolygon(pts, pts, pts.length); - g.dispose(); - } catch (Throwable t) { - } - } - } - - public int print(Graphics g, PageFormat pf, int pageIndex) { - if (pageIndex > 0) { - return NO_SUCH_PAGE; - } - if (peekgraphics == null) { - peekgraphics = g.create(); - } else if (pathgraphics == null) { - pathgraphics = g.create(); - } - Graphics2D g2d = (Graphics2D)g; - g2d.translate(pf.getImageableX(), pf.getImageableY()); - g.drawString("random string", 100,20); - return PAGE_EXISTS; - } - -}