Community
Participate
Working Groups
Created attachment 93220 [details] Shows several bugs, including the browser.print(gc) outside ancestor's clip. Build ID: 3.4M5 Steps To Reproduce: 1. Place a Browser partially outside of its parent bounds. 2. browser.print(gc); 3. Only the visible area gets printed. This is critical for us, as we need a way to print the component, and gc.copyArea() is not an option. We have components floating on top of the browser, and that browser has bounds that do not match the parent's bounds. Note: I believe if someone applies a region (setRegion(x)) on an ancestor, it should print the component entirely. If a setRegion(x) is done on the component itself, it is arguable which approach to take, except that if printing entirely, we can then apply the region on the resulting image, but not the other way round.
Tested on 3.4M6. - On Linux, everything works fine. - On Windows, Button can be printed entirely even if it is outside the ancestor's clip. Browser cannot. Maybe this bug only affects the Browser component, which for us is the most important component to support.
I had a quick go at fixing this and failed. It seems to only affect the browser. It is unlikely I will get to this for 3.4. Do you have a work around?
> Do you have a work > around? Somehow yes: - Take a screen capture. - Place that screen capture in a Shell. - Show this shell. - Remove all clips of the ancestors. - Print the component. - Restore all clips. - Close the Shell and dispose resources. There are many problems: - Substancial delay to the print operation. - Flickering. - If a user happens to click when the shell is shown, it does not work. - Increased memory because of the images that are created. - Potentially many components displayed, some are huge, and printing them quite often make all the above problems to happen frequently. I know that some of my users stress the importance of a fix in that area, so it seems my workaround is not a complete replacement for a fix.
I checked my code and it is even worse (I still had that old attempt in mind when I replied...). Removing the clips of the ancestors was not a viable solution so I used a variation: reparenting. - Take a screen capture. - Create a temporary Shell that will never be shown (prevents appearance in task bar). - Create another temporary dialog Shell with the hidden one as the parent. - Set the bounds of this temporary shell with the onscreen bounds of the Browser. - Place that screen capture in that Shell (a canvas with a paint listener). - Place that screen capture in the parent of the browser (another canvas with a paint listener). - Reparent the browser to the temporary Shell. - Ensure the browser is below the canvas with the screen capture. - Show the temporary shell. - Print the component. - Reparent the browser to its old parent. - Close the Shell, dispose temporary components and resources. I also use setRedraw(false) on several components to reduce flickering. I could not use the parent Shell of the browser as the parent of my temporary shell which is why I create an additional Shell.
The work around sounds insane. Do you need this feature to ship?
(In reply to comment #5) > The work around sounds insane. Do you need this feature to ship? The feature that uses component printing was specifically requested by some users before evaluating our product. With the work around, they could start their evaluation, but they are closely monitoring the status of this bug as it seems the work around does not satisfy them fully.
An update on the importance of this bug: some users want to print the browser component even when it is not visible. It does not work and I think it may be related to this issue. Being able to print the browser to an image is quite important for applications that build thumbnail/previews of links and such. Note that I could not find any work around.
Fixed > 20081127 Christopher, the fix is absolutely insane and likely to be problematic. Please test thouroughly and report your findings in this bug. At that point, we will decide whether to pull the fix, or attempt fixes for the fall out.
Steve, many thanks for having a look at this issue! Maybe your fix is insane, but my tests show that it mostly works. I said mostly because I have a special case in one project (NativeSwing) for which I would have to keep my insane hack. Let me explain: In NativeSwing, I apply clipping to an AWT Panel that contains an AWT Canvas which embeds an SWT Shell that contains an SWT control (the web browser for example). In this configuration, the areas that are clipped do not print (IE and Mozilla). I will try to find if a pure SWT sample can produce the same issue. There are other problems I noticed with the sample attached to this bug report, once you tweak it a little. These issues may have to be entered as different bug reports if this current issue is considered fixed. If you comment the line: shell.open(); then we can test what happens when printing invisible components. IE works, Mozilla on Windows works except the scrollbars that are painted in black, and on Linux nothing paints (including the button). Now that the browser can be printed when invisible, we can think of UI-less applications. I found a bug with IE (unrelated to clipping): it steals the focus from the currently focused application. Adding the following line solves the problem: browser.setEnabled(false); I think this should be internally set so that an invisible IE behaves properly.
> I said mostly because I have a special case in one project (NativeSwing) for > which I would have to keep my insane hack. I understand the issue now: when the control fits in the rectangular area of its component hierarchy, fixPrintWindow in Control.printWidget() is false. This means that if a region clip is applied to some component in the hierarchy, hidden areas will paint as black. It would be desirable that fixPrintWindow be true if a hidden region intersects with the component to paint. I am going to attach a test case in this bug report that shows the problem. I also notice some flickering. It is better than the old behavior though. Maybe there is a way to prevent the components from repainting while reparenting and printing the component. I will see if I can come up with a simple test case that shows this flickering. The bug is partially solved, nevertheless it is not covering all cases. Should we re-open it?
Created attachment 119076 [details] Widget fitting in parent bounds, but with region clip on parent
I see that the fixPrintWindow check is done in Control for any control. You might consider limiting it to the Browser, because a Button that goes beyond its parent bounds or in a shell with a region clip prints properly without the fix.
> I also notice some flickering. I could not find a simple test case to produce the problem so I tried to find and fix that issue. It seems that the following line (line 2051 in Control): SetWindowPos (hwnd, 0, rect1.left, rect1.top, rect1.right - rect1.left, ... causes the flickering. If I replace it with: setRedraw(false); SetWindowPos (hwnd, 0, rect1.left, rect1.top, rect1.right - rect1.left, setRedraw(true); ... then the flickering is gone!
Reopening to make sure we improve the current implementation, and try to fix the remaining issues.
Hi Steve, Any plans to finalize this fix? What is left are: - Limit the fix for the Browser control (not just any control). - Set fixPrintWindow to true if a region clip is set somewhere in the component tree. - Add the setRedraw(false/true) calls as indicated in comment #13 to avoid some flickering. I believe these are quick changes and they are important for us. I am at your disposal to run my various test cases as soon as there are improvements. -Christopher
The bug says "Browser.print(GC) should not use ancestor clip" and that is fixed. > - Limit the fix for the Browser control (not just any control). From memory, the button works because it uses WM_PRINT rather than PrintWindow() because PrintWindow() fails for buttons and group boxes. > Set fixPrintWindow to true if a region clip is set somewhere in the component tree. This is working for me right now. Here is the test code: import org.eclipse.swt.*; import org.eclipse.swt.browser.*; import org.eclipse.swt.events.*; import org.eclipse.swt.graphics.*; import org.eclipse.swt.layout.*; import org.eclipse.swt.widgets.*; public class PR_223590a { public static void main(String[] args) { final Display display = new Display(); final Shell shell = new Shell(display, SWT.NO_TRIM); shell.setLayout(new FillLayout()); final Browser browser = new Browser(shell, SWT.NONE); browser.setUrl("http://www.google.com"); shell.setSize(400, 400); Region region = new Region(); region.add(100, 100, 200, 200); shell.setRegion(region); shell.open(); new Thread() { @Override public void run() { try { sleep(2000); } catch(Exception e) { e.printStackTrace(); } display.asyncExec(new Runnable() { private Image getImage(Control control) { Point size = control.getSize(); Image image = new Image(display, size.x, size.y); GC gc = new GC(image); System.err.println(control.print(gc)); gc.dispose(); return image; } public void run() { Shell newShell = new Shell(shell); newShell.setLayout(new FillLayout()); newShell.setText("Screen captures"); Label browserLabel = new Label(newShell, SWT.BORDER); browserLabel.setImage(getImage(browser)); newShell.setSize(400, 400); newShell.open(); newShell.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { System.exit(0); } }); } }); } }.start(); while(!shell.isDisposed()) { if(!display.readAndDispatch()) display.sleep(); } display.dispose(); } } - Add the setRedraw(false/true) calls as indicated in comment #13 to avoid some flickering. I need a test case before I change code. I'm going to close this bug as FIXED and you can reopen new bugs with test cases that show the problems you are seeing. Not trying to be a pain, but I am insanely busy.
> > Set fixPrintWindow to true if a region clip is set somewhere in the component > tree. > > This is working for me right now. Here is the test code: There is still what I believe is an ancestor clip issue. However, the only test case I have is an SWT-AWT mixing, so I filed bug 267466. > - Add the setRedraw(false/true) calls as indicated in comment #13 to avoid some > flickering. > > I need a test case before I change code. This is not an ancestor issue, but an SWT-AWT mixing one. I filed bug 267468. > Not trying to be a pain, but I am insanely busy. I truly value all the work you are doing. Keep it up! :)