chromiumembedded / cef

Chromium Embedded Framework (CEF). A simple framework for embedding Chromium-based browsers in other applications.
https://bitbucket.org/chromiumembedded/cef/
Other
3.38k stars 467 forks source link

Print Preview still does not load for some websites #3768

Closed jasminjasmin2 closed 1 month ago

jasminjasmin2 commented 3 months ago

Print preview does not work in cefclient 127 and the ''Loading preview.." message never disappears when trying to print https://www.corriere.it/ website but it works for other websites.

Programmatically, in custom windowsless applications calling the PrintToPDF() function, the OnPdfPrintFinished() callback is never called and the printer process never finishes.

To Reproduce Steps to reproduce the behavior:

  1. Launch cefclient.exe --use-alloy-style --enable-print-preview --disable-features=PrintCompositorLPAC
  2. Load https://www.corriere.it/ website in cefclient
  3. Select Print from menu
  4. Print Preview never finishes loading

Versions (please complete the following information):

Additional context

In the case of some other websites, like www.gsp.ro, when trying to print to pdf in custom windows-less applications, setting the browser window rectangle to a quite large height, like 25,000 pixels, also makes the printer process to hang. Not sure if the issues are related. Setting a large browser window for such websites is necessary if the resources loading is triggered only for elements inside the viewport.

The issue does not reproduce with Chrome 127.0.6533.99

jasminjasmin2 commented 3 months ago

The issue is still reproducible with the latest build and it affects websites printing. Do you have any idea how to fix this or is it possible to add a switch to re-enable the old alloy runtime and style to work as it did before 125, at least until the issue is properly fixed in a future version?

jasminjasmin2 commented 3 months ago

I tried to debug this in a third party application and a difference I could notice between the cases when it works and it not works is that after the browser is stopped while waiting for printing to PDF to finish the following error is thrown:

[0818/120745.703:ERROR:print_util.cc(40)] PrintToPDF failed with error: Printing failed [0818/120745.703:FATAL:pdf_print_callback_ctocpp.cc(34)] Check failed: !path.empty().

The output path is set in code and it actually the same code works for other websites. I don't know why that path is not getting to printing process.

jasminjasmin2 commented 3 months ago

What should be done to fix this issue? Could you please help? I don't understand how the output path can get empty in printer process. I tried both with sandbox and no-sandbox, debug and release builds. It is not a Chromium issue and only someone with a deep understanding of CEF code and advanced debugging skills could find the root cause of this and provide a fix. I could not find any switch recently added in Chromium which might change the behavior.

pwerner2100 commented 2 months ago

Unfortunately this regresion seems to persist in the latest 129 release. It could be reproduced with the web pages from report and with many other websites I have tried. Off-screen printing to PDF, which should be an important feature from project description, cannot be reliably used after you made the alloy related changes. Do you have any plan to investigate and fix this in 129 or a in a future release of the project?

jasminjasmin2 commented 2 months ago

Could you please clarify if windowless rendering will be further supported in CEF? Currently the PrintToPDF() calls hangs with many websites as soon as the windowless rendering is enabled. The Alloy runtime was already removed. Do you intend to do the same with Alloy style which would also remove the off-screen rendering since the Alloy style is implicitly used by off-screen rendering? I've seen the issue #3293 refers to use Ozone for off-screen rendering, but it looks like a very long term and complex task. Isn't possible to bring back the old Alloy functionality which was supporting great the off-screen rendering, even if you will mark it as deprecated?

mbragg12 commented 2 months ago

@magreenblatt Do you know what the status of this issue is? I assume it is an actual defect and not something that is unsupported. Similar to the initial report, tinkering with 128 and --use-alloy-style, I can print simple sites like google but on large/complex sites PrintToPdf hangs.

Not sure it helps at all but if you navigate away from the site being printed, the DCHECK(!path.empty()); in OnPdfPrintFinished in pdf_print_callback_ctocpp.cc gets hit. The top of the stack for that is:

    libcef.dll!CefPdfPrintCallbackCToCpp::OnPdfPrintFinished(const CefStringBase<CefStringTraitsUTF16> & path, bool ok) Line 35 C++
    libcef.dll!print_util::`anonymous namespace'::OnPDFCreated(const CefStringBase<CefStringTraitsUTF16> & path, scoped_refptr<CefPdfPrintCallback> callback, print_to_pdf::PdfPrintResult print_result, scoped_refptr<base::RefCountedMemory> data) Line 42    C++
    libcef.dll!base::OnceCallback<void (int, scoped_refptr<net::IOBuffer>)>::Run(int args, scoped_refptr<net::IOBuffer> args) Line 156  C++
    [Inline Frame] libcef.dll!print_to_pdf::PdfPrintJob::FailJob(print_to_pdf::PdfPrintResult result) Line 145  C++
    libcef.dll!print_to_pdf::PdfPrintJob::RenderFrameDeleted(content::RenderFrameHost * render_frame_host) Line 155 C++
    libcef.dll!content::WebContentsImpl::WebContentsObserverList::NotifyObservers<void (content::WebContentsObserver::*)(content::RenderFrameHost *),content::RenderFrameHostImpl *>(void(content::WebContentsObserver::*)(content::RenderFrameHost *) func, content::RenderFrameHostImpl * && args) Line 1678  C++
    libcef.dll!content::WebContentsImpl::RenderFrameDeleted(content::RenderFrameHostImpl * render_frame_host) Line 7895 C++
    libcef.dll!content::RenderFrameHostImpl::~RenderFrameHostImpl() Line 2153   C++
jasminjasmin2 commented 2 months ago

This issues is still reproducible in the latest build. Almost two months passed since the initial report. @magreenblatt : Could you please clarify if there is any plan to fix this critical issue with off-screen printing in the future releases or the functionality will be removed ? In the current status is practically unusable and without your great expertise I don't think somebody else can fix it.

jasminjasmin2 commented 1 month ago

The same issue occurs when using the 'Page.printToPDF' method from DevTools protocol. The method closure callback is never invoked. If the windowsless rendering is disabled, the callback is invoked. The 'Page.captureScreenshot' method works properly instead, so it's only a problem with printing to PDF method. Could you guide on how to debug this?

edgardogho commented 1 month ago

I had this issue on linux with PrintToPDF not completing for some sites (specially the ones with google ads). The work around I found is described here: https://www.magpcss.org/ceforum/viewtopic.php?f=6&t=19827&start=10 The /components/services/print_compositor/print_compositor_impl.cc on seems to wait for ever in a part of the code, I simply skipped the whole thing as a workaround. There will be parts that will not render (the ones that hang) but the rest will render fine on the PDF. I get the same problem now on 129. I applied the same workaround and worked fine.

mbragg12 commented 1 month ago

That definitely seems to be the issue. I added some logs on the IsReadyToComposite and if that returns false, the print "hangs". Now to decide what to do with this information.

mbragg12 commented 1 month ago

edgardogho's work around definitely improves the situation (thanks for that) but there are still issues. It seems to consistently create the PDF. The PDF is usually wrong, missing images and such. The completion callback also doesn't always get called. In the case of the print preview, it shows an error saying the preview failed.

jasminjasmin2 commented 1 month ago

Yes, I can also confirm the workaround allows the print to PDF to finish even if with missing elements. Thanks @edgardogho for this. It is not clear yet why it works (without any change) when the windowsless rendering is disabled. It seems that Alloy style still plays a role in this issue and it needs further investigation for a complete fix.

magreenblatt commented 1 month ago

@jasminjasmin2 can you test if this issue is resolved in M130 (beta)? This comment suggests that it might be.

jasminjasmin2 commented 1 month ago

Unfortunately it still reproduces in 130.3 both with cefclient print preview and with my windowless print to PDF application. The workaround suggested by @edgardogho allows printing to finish both in the case of this report and of the new #3798 report, but the frame content is missing.

jasminjasmin2 commented 1 month ago

@magreenblatt Marshall, could you please take a look into this? There was a good progress here to workaround this issue and to isolate the it, but we simply could not figure out the root cause. What would you suggest to try further to debug this? It seems to be related to frames origin but why does the same code works without problems when just windowless printing is disabled? How does windowless printing in CEF relate to frames origin? Is the switch to chrome runtime and the removal of alloy runtime the only cause for this issue or it is just a coincidence and some other Chromium changes triggered this problem? Is there any long term plan to also replace the Alloy style in windowless rendering?

magreenblatt commented 1 month ago

why does the same code works without problems when just windowless printing is disabled?

What do you mean by this? What specific problems are you referring to? Is that with or without the changes to print_compositor_impl.cc mentioned above? Are you able to reproduce the problem in cefclient? If so, with what command-line flags?

Is there any long term plan to also replace the Alloy style in windowless rendering?

Do you mean support Chrome style with windowless rendering? Maybe, see issue #3263.

jasminjasmin2 commented 1 month ago

What do you mean by this? What specific problems are you referring to? Is that with or without the changes to print_compositor_impl.cc mentioned above? Are you able to reproduce the problem in cefclient? If so, with what command-line flags?

I was referring to the case of a third-party application that uses the PrintToPDF() function to create PDFs offscreen, without the changes to print_compositor_impl.cc. Those changes would indeed allow printing to PDF to finish, but with missing content.

If windowless rendering is enabled in such an application by setting the flag windowless_rendering_enabled = true, then the printing hangs, and the OnPdfPrintFinished() callback is never called when I print https://www.corriere.it/ or other HTML pages with sandboxed iframes.

If windowless printing is disabled by simply setting windowless_rendering_enabled = false, the PDF is created, but a browser window is displayed on the screen while printing, which is not the intended behavior.

A similar issue is reproducible in cefclient, launched with the command:

cefclient.exe --use-alloy-style --enable-print-preview --disable-features=PrintCompositorLPAC

If you load the https://www.corriere.it/ web page and try to print it, Print Preview will hang. This was the initial bug report, which is still reproducible with the latest builds of CEF.

Do you mean support Chrome style with windowless rendering? Maybe, see issue https://github.com/chromiumembedded/cef/issues/3263.

Yes, is this a long-term plan, or could it be implemented in the near future?

mbragg12 commented 1 month ago

Just to clarify, this happens on a lot of other sites as well. I have been able to reliably reproduce the issue on tmz.com and digg.com. Many other sites exhibit the issue to some degree. I've seen it with yahoo.com, aol.com, cnn.com and some amazon.com product pages. This was with the --use-alloy-style in the cefclient and doing a print to pdf. I was going to try and do some comparisons between what is printed using Chrome and the cefclient with --use-alloy-style and the print_compositor_impl.cc work around sometime this week. With any luck if we can identify what subframes aren't printing; we can find some commonality to identify the actual issue.

magreenblatt commented 1 month ago

Do you mean support Chrome style with windowless rendering? Maybe, see issue https://github.com/chromiumembedded/cef/issues/3263.

Yes, is this a long-term plan, or could it be implemented in the near future?

Long-term possibility, not currently planned.

mbragg12 commented 1 month ago

So not sure what it really means yet but based on the conversations and after some tinkering this is about the most minimalistic way of reproducing the issue I've found. This is with 130.0.5.

I created an HTML file with the following bit of (crappy) code:

<!DOCTYPE html>
<html>
<head>
    <title>iFrame Print test</title>
</head>

<body style="text-align: center">
    <h2>HTML Tag</h2>
    <iframe src="https://www.google.com" height="300" width="400">
    </iframe>
</body></html>

The code can be tweaked to make it actually "work" but the behavior is generally the same.

I run the client with cefclient.exe --enable-print-preview --disable-features=PrintCompositorLPAC, open the test file and select Tests->print. The result is image

I run the client with cefclient.exe --use-alloy-style --enable-print-preview --disable-features=PrintCompositorLPAC, open the test file and select Tests->print. The result is image It will sit there saying "loading preview..." forever. If you select save, the app effectively hangs.

On a build with the print_compositor_impl tweak, if I run the client with cefclient.exe --use-alloy-style --enable-print-preview --disable-features=PrintCompositorLPAC, open the test file and select Tests->print. The result is image

I assume print to pdf uses the same code paths. It behaves in a consistent manner to the print preview. The PDF looks the same when it produces one and in the fail case nothing is ever produced.

jasminjasmin2 commented 1 month ago

Just to clarify, this happens on a lot of other sites as well. I have been able to reliably reproduce the issue on tmz.com and digg.com. Many other sites exhibit the issue to some degree. I've seen it with yahoo.com, aol.com, cnn.com and some amazon.com product pages.

Yes, the off-screen printing to PDF has been nearly unusable for the past few months in the latest versions of CEF. I thought it was a key feature of the project, but unfortunately it doesn't seem to be a priority for the project maintainers at this moment and the future of it is uncertain.

magreenblatt commented 1 month ago

Thanks everyone for your feedback on this issue. The related area of code (printing OOPIFs) is complicated, as shown in the design diagram. The proposed workaround indicates that something in this system is not working as expected (e.g. OOPIFs are never signaled as ready). Unfortunately I don't personally have time to dive into this currently. You (anyone) are welcome to take some time to properly understand and debug the Chromium code in this area. Given that Chrome style behavior appears to be working, comparing the execution paths for Chrome and Alloy style browsers in CEF side-by-side might provide the vital clue.

mbragg12 commented 1 month ago

@magreenblatt I've identified the root issue that is causing this problem with printing. AlloyBrowserHostImpl needs to implement PrintCrossProcessSubframe or something to that effect. Basic overview: In WebContentsImpl::PrintCrossProcessSubframe the last call is to delegate_->PrintCrossProcessSubframe. The Chrome renderer delegate has that hooked up. The alloy version just calls the base classes version which does nothing. Not sure of much more at this point like if anything else from WebContentsDelegate needs to be hooked up, but at least we know why it works for Chrome and not Alloy.

magreenblatt commented 1 month ago

@mbragg12 Good find. It looks like the related Chromium commit is https://crrev.com/5bb6597491. Can you try copy/pasting the Browser::PrintCrossProcessSubframe implementation to a new AlloyBrowserHostImpl::PrintCrossProcessSubframe method?

mbragg12 commented 1 month ago

I duped the code fromchrome/browser/ui/browser.ccand it appears to be working. My code base is a little bit mangled from the logging and stuff to track this down, so definitely needs more testing to be certain. I can make a PR once I get that cleaned up or here is the patch if anyone wants to try in the mean time.


diff --git a/libcef/browser/alloy/alloy_browser_host_impl.cc b/libcef/browser/alloy/alloy_browser_host_impl.cc
index 135b6cebb..63d1ba47a 100644
--- a/libcef/browser/alloy/alloy_browser_host_impl.cc
+++ b/libcef/browser/alloy/alloy_browser_host_impl.cc
@@ -35,6 +35,7 @@
 #include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
 #include "chrome/common/webui_url_constants.h"
 #include "components/input/native_web_keyboard_event.h"
+#include "components/printing/browser/print_composite_client.h"
 #include "components/zoom/page_zoom.h"
 #include "content/browser/gpu/compositor_util.h"
 #include "content/public/browser/desktop_media_id.h"
@@ -922,6 +923,16 @@ bool AlloyBrowserHostImpl::IsAudioMuted() {
 // content::WebContentsDelegate methods.
 // -----------------------------------------------------------------------------

+void AlloyBrowserHostImpl::PrintCrossProcessSubframe(
+    content::WebContents* web_contents,
+    const gfx::Rect& rect,
+    int document_cookie,
+    content::RenderFrameHost* subframe_host) const {
+  auto* client = printing::PrintCompositeClient::FromWebContents(web_contents);
+  if (client)
+    client->PrintCrossProcessSubframe(rect, document_cookie, subframe_host);
+}
+
 content::WebContents* AlloyBrowserHostImpl::OpenURLFromTab(
     content::WebContents* source,
     const content::OpenURLParams& params,
diff --git a/libcef/browser/alloy/alloy_browser_host_impl.h b/libcef/browser/alloy/alloy_browser_host_impl.h
index 9c2a409fd..314daa12b 100644
--- a/libcef/browser/alloy/alloy_browser_host_impl.h
+++ b/libcef/browser/alloy/alloy_browser_host_impl.h
@@ -271,6 +271,10 @@ class AlloyBrowserHostImpl : public CefBrowserHostBase,
   void DraggableRegionsChanged(
       const std::vector<blink::mojom::DraggableRegionPtr>& regions,
       content::WebContents* contents) override;
+  void PrintCrossProcessSubframe(content::WebContents* web_contents,
+                                         const gfx::Rect& rect,
+                                         int document_cookie,
+                                         content::RenderFrameHost* subframe_host) const override;

   // content::WebContentsObserver methods.
   using content::WebContentsObserver::BeforeUnloadFired;