JDK-6719382 : Printing of AWT components on windows is not working
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 6u10
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • OS: windows
  • CPU: generic,x86
  • Submitted: 2008-06-26
  • Updated: 2011-01-19
  • Resolved: 2008-07-04
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6 JDK 7
6u10 b27Fixed 7Fixed
Related Reports
Relates :  
Description
Printing of AWT componenst is not working both with old and new Plug-in on IE6/IE7, FF2/FF3 and mozilla browsers. This regression got introduced in 6u10-b12. Everything worked fine till 6u10-b11. With the current build printing is working fine if applet contains Swing component or painting is done directly on Applet panel.

Steps to reproduce:
-----------
1) Install latest 6u10
2) Try to load any of the following applets
http://java.sun.com/products/plugin/1.5.0/demos/applets/ArcTest/example1.html
(this applet contains AWT Text fields and Buttons)
or 
http://sqeweb.sfbay.sun.com/deployment2/jitu/plug-bug/ALC/PrintThreadNew.html

3) Try to print applets using Browser File > Print menu option

If AWT components fails to print then bug is reproduced

Repeat all the above steps with old Plug-in 

Non-AWT applets(Printing should work fine applets listed below)
http://java.sun.com/products/plugin/1.5.0/demos/jfc/SwingSet2/SwingSet2.html
http://java.sun.com/products/plugin/1.5.0/demos/applets/Clock/example1.html
http://java.sun.com/products/plugin/1.5.0/demos/applets/SpreadSheet/example1.html
http://java.sun.com/products/plugin/1.5.0/demos/applets/BarChart/example1.html

Comments
EVALUATION The AwtComponent::CreatePrintedPixels() function did not ever write the alpha component of the printed pixels. Hence, the alpha in the pixels array was always zero. It didn't cause problems before the fix for 6648996 because TYPE_INT_RGB kind of BufferedImage was used which obviously ignored the alpha color component (when using its setRGB() method). However, when using the TYPE_INT_ARGB type, the BufferedImage started to respect the alpha component. As all alpha components were zeros, no heavyweight content was printed. The suggested fix resolves this issue manually filling the alpha color component when handling the WM_PRINT message for heavyweight components.
30-06-2008

SUGGESTED FIX --- old/src/windows/native/sun/windows/awt_BitmapUtil.cpp 2008-07-01 16:53:17.000000000 +0400 +++ new/src/windows/native/sun/windows/awt_BitmapUtil.cpp 2008-07-01 16:53:17.000000000 +0400 @@ -396,3 +396,23 @@ return hDstBitmap; } +/** + * Creates a 32 bit ARGB bitmap. Returns the bitmap handle. The *bitmapBits + * receives a pointer to the location of the DIB bit values. + */ +HBITMAP BitmapUtil::CreateARGBBitmap(int width, int height, void ** bitmapBits) +{ + BITMAPINFOHEADER bmi; + + ::ZeroMemory(&bmi, sizeof(bmi)); + bmi.biSize = sizeof(bmi); + bmi.biWidth = width; + bmi.biHeight = -height; + bmi.biPlanes = 1; + bmi.biBitCount = 32; + bmi.biCompression = BI_RGB; + + return ::CreateDIBSection(NULL, (BITMAPINFO *) & bmi, DIB_RGB_COLORS, + bitmapBits, NULL, 0); +} + --- old/src/windows/native/sun/windows/awt_BitmapUtil.h 2008-07-01 16:53:17.000000000 +0400 +++ new/src/windows/native/sun/windows/awt_BitmapUtil.h 2008-07-01 16:53:17.000000000 +0400 @@ -47,6 +47,12 @@ * simply makes a plain copy of the source without any blending. */ static HBITMAP BlendCopy(HBITMAP hSrcBitmap, COLORREF blendColor, BYTE alpha); + + /** + * Creates a 32 bit ARGB bitmap. Returns the bitmap handle. The *bitmapBits + * receives a pointer to the location of the DIB bit values. + */ + static HBITMAP CreateARGBBitmap(int width, int height, void ** bitmapBits); }; #endif --- old/src/windows/native/sun/windows/awt_Component.cpp 2008-07-01 16:53:17.000000000 +0400 +++ new/src/windows/native/sun/windows/awt_Component.cpp 2008-07-01 16:53:17.000000000 +0400 @@ -11,6 +11,7 @@ #include "jlong.h" #include "awt_AWTEvent.h" +#include "awt_BitmapUtil.h" #include "awt_Component.h" #include "awt_Cursor.h" #include "awt_Dimension.h" @@ -4825,6 +4826,27 @@ return hdc; } +void AwtComponent::FillBackground(HDC hDC, SIZE &size) +{ + RECT eraseR = { 0, 0, size.cx, size.cy }; + VERIFY(::FillRect(hDC, &eraseR, GetBackgroundBrush())); +} + +void AwtComponent::FillAlpha(void *bitmapBits, SIZE &size, BYTE alpha) +{ + if (!bitmapBits) { + return; + } + + DWORD* dest = (DWORD*)bitmapBits; + //XXX: might be optimized to use one loop (int i = cy*cx; i > 0; i++). + for (int i = 0; i < size.cy; i++ ) { + for (int j = 0; j < size.cx; j++ ) { + ((BYTE*)(dest++))[3] = alpha; + } + } +} + jintArray AwtComponent::CreatePrintedPixels(SIZE &loc, SIZE &size) { JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); @@ -4837,12 +4859,13 @@ return NULL; } HDC hMemoryDC = ::CreateCompatibleDC(hdc); - HBITMAP hBitmap = ::CreateCompatibleBitmap(hdc, size.cx, size.cy); + void *bitmapBits = NULL; + HBITMAP hBitmap = BitmapUtil::CreateARGBBitmap(size.cx, size.cy, + &bitmapBits); HBITMAP hOldBitmap = (HBITMAP)::SelectObject(hMemoryDC, hBitmap); SendMessage(WM_AWT_RELEASEDC, (WPARAM)hdc); - RECT eraseR = { 0, 0, size.cx, size.cy }; - VERIFY(::FillRect(hMemoryDC, &eraseR, GetBackgroundBrush())); + FillBackground(hMemoryDC, size); VERIFY(::SetWindowOrgEx(hMemoryDC, loc.cx, loc.cy, NULL)); @@ -4850,6 +4873,14 @@ // above. SendMessage(WM_PRINT, (WPARAM)hMemoryDC, PRF_CLIENT | PRF_NONCLIENT); + // First make sure the system completed any drawing to the bitmap. + ::GdiFlush(); + + // WM_PRINT does not fill the alpha-channel of the ARGB bitmap + // leaving it equal to zero. Hence we need to fill it manually. Otherwise + // the pixels will be considered transparent when interpreting the data. + FillAlpha(bitmapBits, size, 0xFF); + ::SelectObject(hMemoryDC, hOldBitmap); BITMAPINFO bmi; --- old/src/windows/native/sun/windows/awt_Component.h 2008-07-01 16:53:18.000000000 +0400 +++ new/src/windows/native/sun/windows/awt_Component.h 2008-07-01 16:53:18.000000000 +0400 @@ -576,6 +576,11 @@ void UpdateColorModel(); +protected: + //These functions are overridden in AwtWindow to handle non-opaque windows. + virtual void FillBackground(HDC hDC, SIZE &size); + virtual void FillAlpha(void *bitmapBits, SIZE &size, BYTE alpha); +public: jintArray CreatePrintedPixels(SIZE &loc, SIZE &size); static void * GetNativeFocusOwner(); --- old/src/windows/native/sun/windows/awt_Window.cpp 2008-07-01 16:53:18.000000000 +0400 +++ new/src/windows/native/sun/windows/awt_Window.cpp 2008-07-01 16:53:18.000000000 +0400 @@ -2772,6 +2772,20 @@ ::LeaveCriticalSection(&contentBitmapCS); } +void AwtWindow::FillBackground(HDC hDC, SIZE &size) +{ + if (isOpaque()) { + AwtCanvas::FillBackground(hDC, size); + } +} + +void AwtWindow::FillAlpha(void *bitmapBits, SIZE &size, BYTE alpha) +{ + if (isOpaque()) { + AwtCanvas::FillAlpha(bitmapBits, size, alpha); + } +} + extern "C" { /* --- old/src/windows/native/sun/windows/awt_Window.h 2008-07-01 16:53:19.000000000 +0400 +++ new/src/windows/native/sun/windows/awt_Window.h 2008-07-01 16:53:19.000000000 +0400 @@ -291,6 +291,11 @@ return warningString != NULL; } + //These are used in AwtComponent::CreatePrintedPixels. They are overridden + //here to handle non-opaque windows. + virtual void FillBackground(HDC hDC, SIZE &size); + virtual void FillAlpha(void *bitmapBits, SIZE &size, BYTE alpha); + private: int m_screenNum;
30-06-2008

EVALUATION This is a regression of the fix for 6648996 (Frame.printAll() invoked on a non-opaque window prints black background). The problem is the type of the BufferedImage created in the WComponentPeer.print() method. It used to be BufferedImage.TYPE_INT_RGB, but with the fix for 6648996 it changed to BufferedImage.TYPE_INT_ARGB. W/o that change the non-opaque windows got printed with a black background instead of transparent background. It seems that the problem is the createPrintedPixels() method which draws heavyweight components with alpha value of zero. That's why they probably do not get printed.
27-06-2008

EVALUATION Its not just applets. I'm seeing lots of problems in a standalone app using test/java/awt/PrintJob/PrintComponentTest/PrintComponentTest.java I suspect a z-ordering issue as WComponentPeer.createPrintedPixels() is apparently returning some data.
26-06-2008