Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8235831

First printed page blank after resizing WebView

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: P4 P4
    • tbd
    • jfx11, 8
    • javafx
    • web

      DESCRIPTION
      -----------
      JavaFX allows to print any Node through the Print API, even when the application is running in headless mode.

      However, in headless mode if the `PrinterJob#printPage` method is called on a WebView after it has been resized, the job doesn't print anything. This only happens for the first page. Subsequent prints after the first print are correct.

      The issue only happens in headless mode for the first print after the WebView is resized.

      PLATFORM
      --------
      Can be reproduced on MacOS Catalina, Ubuntu 18.04 and Windows 10 Using Oracle Java 8 (64-bit) and AdoptOpenJDK 11

      FREQUENCY
      ---------
      Can always be reproduced

      STEPS TO REPRODUCE THE PROBLEM
      ------------------------------
      1 Set the default printer to a "document printer"
      2 Run the attached application
      3 The application tries to print 4 pages and shows a dialog to save each one of them
      4 First and fourth print-jobs prints the content of the WebView. However, second and third doesn't

      EXPECTED vs ACTUAL
      ------------------
      EXPECTED
      Print job should always print the content of the WebView
      ACTUAL -
      The first print job after WebView resize doesn't print anything


      ---------- BEGIN SOURCE ----------
      import javafx.animation.PauseTransition;
      import javafx.application.Application;
      import javafx.application.Platform;
      import javafx.beans.value.ChangeListener;
      import javafx.concurrent.Worker;
      import javafx.geometry.Dimension2D;
      import javafx.print.Printer;
      import javafx.print.PrinterJob;
      import javafx.scene.Scene;
      import javafx.scene.web.WebView;
      import javafx.stage.Stage;
      import javafx.util.Duration;

      import java.util.concurrent.CountDownLatch;

      public class WebViewPrintBug extends Application {

          private static final String HTML_TEMPLATE = "<html><body>%s</body></html>";

          private static final CountDownLatch startup = new CountDownLatch(1);

          private static WebView webView;
          private static Stage stage;
          private static Dimension2D dimensions;

          private static PauseTransition transition;
          private static CountDownLatch printed;


          public static void main(String[] args) throws Exception {
              // start JFX
              new Thread(() -> Application.launch(WebViewPrintBug.class)).start();
              startup.await();

              //try some prints
              Printer printer = Printer.getDefaultPrinter();

              //prints fine
              printed = new CountDownLatch(1);
              dimensions = new Dimension2D(720, 960);
              print(printer, String.format(HTML_TEMPLATE, "<h2>Test Page 1</h2><div>Content goes here</div>"));
              printed.await();

              //prints blank
              printed = new CountDownLatch(1);
              dimensions = new Dimension2D(640, 960);
              print(printer, String.format(HTML_TEMPLATE, "<h2>Test Page 2</h2><div>Can you see me?</div>"));
              printed.await();

              //also prints blank
              printed = new CountDownLatch(1);
              dimensions = new Dimension2D(640, 800);
              print(printer, String.format(HTML_TEMPLATE, "<h2>Test Page 3</h2><div>Spooky ghost image</div>"));
              printed.await();

              //same dimensions > prints fine
              printed = new CountDownLatch(1);
              print(printer, String.format(HTML_TEMPLATE, "<h2>Test Page 4</h2><div>Visible content</div>"));
              printed.await();

              System.out.println("Done");
              Platform.exit();
          }


          /** Called by jfx thread on startup */
          @Override
          public void start(Stage st) {
              webView = new WebView();
              st.setScene(new Scene(webView));
              stage = st;

              //setup load listeners
              Worker<Void> worker = webView.getEngine().getLoadWorker();
              worker.stateProperty().addListener(stateListener);
              worker.exceptionProperty().addListener((obs, oldEx, newEx) -> {
                  if (newEx != null) { newEx.printStackTrace(); }
              });

              //prevents JavaFX from shutting down when hiding window
              Platform.setImplicitExit(false);

              System.out.println("Started JFX");
              startup.countDown();
          }

          /** Called by jfx thread on content load */
          private static ChangeListener<Worker.State> stateListener = (ov, oldState, newState) -> {
              if (newState == Worker.State.SUCCEEDED) {
                  //resize the view
                  System.out.println(dimensions);
                  webView.setMinSize(dimensions.getWidth(), dimensions.getHeight());
                  webView.setPrefSize(dimensions.getWidth(), dimensions.getHeight());
                  webView.setMaxSize(dimensions.getWidth(), dimensions.getHeight());
                  webView.autosize();

                  //hand off to print lambda
                  transition.playFromStart();

                  //showing stage at this point prevents blank pages, but breaks on headless environments
                  stage.show();
              }
          };

          /** Our call to load pages and finalize printing */
          private static void print(Printer printer, String content) {
              //note - extending duration doesn't seem to have an effect on blank pages
              transition = new PauseTransition(Duration.millis(100));
              transition.setOnFinished(evt -> {
                  PrinterJob job = PrinterJob.createPrinterJob(printer);

                  Platform.runLater(() -> {
                      stage.hide();

                      System.out.println("Starting print");
                      System.out.println((String) webView.getEngine().executeScript("document.documentElement.outerHTML"));
                      job.printPage(webView);
                      job.endJob();

                      printed.countDown();
                  });
              });

              //reset webview and start loading
              Platform.runLater(() -> {
                  webView.getTransforms().clear();
                  webView.getEngine().loadContent(content, "text/html");
              });
          }
      }
      ---------- END SOURCE ----------

            Unassigned Unassigned
            jvos Johan Vos
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated: