blob: e08b5197390b249f584c192f0ef256e78b7eacd6 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_WEBUI_PRINT_PREVIEW_PRINT_PREVIEW_UI_H_
#define CHROME_BROWSER_UI_WEBUI_PRINT_PREVIEW_PRINT_PREVIEW_UI_H_
#include <stdint.h>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "base/containers/span.h"
#include "base/functional/callback_forward.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/read_only_shared_memory_region.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "chrome/browser/ui/webui/constrained_web_dialog_ui.h"
#include "chrome/services/printing/public/mojom/pdf_nup_converter.mojom.h"
#include "components/printing/common/print.mojom.h"
#include "components/services/print_compositor/public/mojom/print_compositor.mojom.h"
#include "content/public/browser/web_ui_controller.h"
#include "content/public/browser/webui_config.h"
#include "mojo/public/cpp/bindings/associated_receiver.h"
#include "printing/buildflags/buildflags.h"
#include "printing/mojom/print.mojom-forward.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/size.h"
#if BUILDFLAG(ENABLE_OOP_PRINTING)
#include "chrome/browser/printing/print_backend_service_manager.h"
#endif
class GURL;
namespace base {
class FilePath;
class RefCountedMemory;
} // namespace base
namespace content {
class BrowserContext;
} // namespace content
namespace printing {
class PrintPreviewHandler;
class PrintPreviewUI;
class PrintPreviewUIConfig
: public content::DefaultWebUIConfig<PrintPreviewUI> {
public:
PrintPreviewUIConfig();
~PrintPreviewUIConfig() override;
// content::DefaultWebUIConfig:
bool IsWebUIEnabled(content::BrowserContext* browser_context) override;
bool ShouldHandleURL(const GURL& url) override;
};
// PrintPreviewUI lives on the UI thread.
class PrintPreviewUI : public ConstrainedWebDialogUI,
public mojom::PrintPreviewUI {
public:
explicit PrintPreviewUI(content::WebUI* web_ui);
PrintPreviewUI(const PrintPreviewUI&) = delete;
PrintPreviewUI& operator=(const PrintPreviewUI&) = delete;
~PrintPreviewUI() override;
mojo::PendingAssociatedRemote<mojom::PrintPreviewUI> BindPrintPreviewUI();
// Gets the print preview `data`. `index` is zero-based, and can be
// `COMPLETE_PREVIEW_DOCUMENT_INDEX` to get the entire preview document.
virtual scoped_refptr<base::RefCountedMemory> GetPrintPreviewDataForIndex(
int index) const;
// printing::mojo::PrintPreviewUI:
void SetOptionsFromDocument(const mojom::OptionsFromDocumentParamsPtr params,
int32_t request_id) override;
void DidPrepareDocumentForPreview(int32_t document_cookie,
int32_t request_id) override;
void DidPreviewPage(mojom::DidPreviewPageParamsPtr params,
int32_t request_id) override;
void MetafileReadyForPrinting(mojom::DidPreviewDocumentParamsPtr params,
int32_t request_id) override;
void PrintPreviewFailed(int32_t document_cookie, int32_t request_id) override;
void PrintPreviewCancelled(int32_t document_cookie,
int32_t request_id) override;
void PrinterSettingsInvalid(int32_t document_cookie,
int32_t request_id) override;
void DidGetDefaultPageLayout(mojom::PageSizeMarginsPtr page_layout_in_points,
const gfx::RectF& printable_area_in_points,
bool all_pages_have_custom_size,
bool all_pages_have_custom_orientation,
int32_t request_id) override;
void DidStartPreview(mojom::DidStartPreviewParamsPtr params,
int32_t request_id) override;
bool IsBound() const;
// Setters
void SetInitiatorTitle(const std::u16string& initiator_title);
const std::u16string& initiator_title() const { return initiator_title_; }
int pages_per_sheet() const { return pages_per_sheet_; }
const gfx::Rect& printable_area() const { return printable_area_; }
const gfx::Size& page_size() const { return page_size_; }
PrintPreviewHandler* handler() const { return handler_; }
// Returns true if `page_index` is the last page in `pages_to_render_`.
// `page_index` is a 0-based.
bool LastPageComposited(uint32_t page_index) const;
// Get the 0-based index of the `page_index` in `pages_to_render_`.
// `page_index` is a 0-based.
uint32_t GetPageToNupConvertIndex(uint32_t page_index) const;
std::vector<base::ReadOnlySharedMemoryRegion> TakePagesForNupConvert();
// Save pdf pages temporarily before ready to do N-up conversion.
void AddPdfPageForNupConversion(base::ReadOnlySharedMemoryRegion pdf_page);
// Determines whether to cancel a print preview request based on the request
// id.
static bool ShouldCancelRequest(const std::optional<int32_t>& preview_ui_id,
int request_id);
// Returns an id to uniquely identify this PrintPreviewUI.
std::optional<int32_t> GetIDForPrintPreviewUI() const;
// Notifies the Web UI of a print preview request with |request_id|.
virtual void OnPrintPreviewRequest(int request_id);
// Notifies the Web UI that the 0-based page `page_index` rendering is being
// processed and an OnPendingPreviewPage() call is imminent. Returns whether
// `page_index` is the expected page.
bool OnPendingPreviewPage(uint32_t page_index);
// Notifies the Web UI that the print preview failed to render for the request
// with id = |request_id|.
void OnPrintPreviewFailed(int request_id);
// Notified the Web UI that this print preview dialog's RenderProcess has been
// closed, which may occur for several reasons, e.g. tab closure or crash.
void OnPrintPreviewDialogClosed();
// Notifies the Web UI that initiator is closed, so we can disable all the
// controls that need the initiator for generating the preview data.
void OnInitiatorClosed();
// Notifies the Web UI to cancel the pending preview request.
virtual void OnCancelPendingPreviewRequest();
// Hides the print preview dialog.
virtual void OnHidePreviewDialog();
// Closes the print preview dialog.
virtual void OnClosePrintPreviewDialog();
// Allows tests to wait until the print preview dialog is loaded.
class TestDelegate {
public:
// Provides the total number of pages requested for the preview.
virtual void DidGetPreviewPageCount(uint32_t page_count) {}
// Notifies that a page was rendered for the preview. This occurs after
// any possible N-up processing, so each rendered page could represent
// multiple pages that were counted in `DidGetPreviewPageCount()`.
virtual void DidRenderPreviewPage(content::WebContents* preview_dialog) {}
// Notifies that the document to print from preview is ready. This occurs
// after any possible N-up processing.
virtual void PreviewDocumentReady(content::WebContents* preview_dialog,
base::span<const uint8_t> data) {}
protected:
virtual ~TestDelegate() = default;
};
static void SetDelegateForTesting(TestDelegate* delegate);
// Allows for tests to set a file path to print a PDF to. This also initiates
// the printing without having to click a button on the print preview dialog.
void SetSelectedFileForTesting(const base::FilePath& path);
// Passes |closure| to PrintPreviewHandler::SetPdfSavedClosureForTesting().
void SetPdfSavedClosureForTesting(base::OnceClosure closure);
// See SetPrintPreviewDataForIndex().
void SetPrintPreviewDataForIndexForTest(
int index,
scoped_refptr<base::RefCountedMemory> data);
// See ClearAllPreviewData().
void ClearAllPreviewDataForTest();
// Sets a new valid Print Preview UI ID for this instance. Called by
// PrintPreviewHandler in OnJavascriptAllowed().
void SetPreviewUIId();
// Clears the UI ID. Called by PrintPreviewHandler in
// OnJavascriptDisallowed().
void ClearPreviewUIId();
protected:
// Alternate constructor for tests
PrintPreviewUI(content::WebUI* web_ui,
std::unique_ptr<PrintPreviewHandler> handler);
private:
FRIEND_TEST_ALL_PREFIXES(PrintPreviewDialogControllerUnitTest,
TitleAfterReload);
FRIEND_TEST_ALL_PREFIXES(PrintPreviewUIUnitTest,
PrintPreviewFailureCancelsPendingActions);
// Sets the print preview |data|. |index| is zero-based, and can be
// |COMPLETE_PREVIEW_DOCUMENT_INDEX| to set the entire preview document.
void SetPrintPreviewDataForIndex(int index,
scoped_refptr<base::RefCountedMemory> data);
// Clear the existing print preview data.
void ClearAllPreviewData();
// Notifies the Web UI that the 0-based page `page_index` has been rendered.
// `request_id` indicates which request resulted in this response.
void NotifyUIPreviewPageReady(
uint32_t page_index,
int request_id,
scoped_refptr<base::RefCountedMemory> data_bytes);
// Notifies the Web UI renderer that preview data is available. |request_id|
// indicates which request resulted in this response.
void NotifyUIPreviewDocumentReady(
int request_id,
scoped_refptr<base::RefCountedMemory> data_bytes);
bool ShouldUseCompositor() const;
// Callbacks for print compositor client.
void OnPrepareForDocumentToPdfDone(int32_t request_id,
mojom::PrintCompositor::Status status);
void OnCompositePdfPageDone(uint32_t page_index,
int32_t document_cookie,
int32_t request_id,
mojom::PrintCompositor::Status status,
base::ReadOnlySharedMemoryRegion region);
void OnNupPdfConvertDone(uint32_t page_index,
int32_t request_id,
mojom::PdfNupConverter::Status status,
base::ReadOnlySharedMemoryRegion region);
void OnNupPdfDocumentConvertDone(int32_t request_id,
mojom::PdfNupConverter::Status status,
base::ReadOnlySharedMemoryRegion region);
void OnCompositeToPdfDone(int document_cookie,
int32_t request_id,
mojom::PrintCompositor::Status status,
base::ReadOnlySharedMemoryRegion region);
#if BUILDFLAG(ENABLE_OOP_PRINTING)
// Registers this PrintPreviewUI with the PrintBackendServiceManager. It is
// beneficial to have the Print Backend service be present and ready for at
// least as long as this UI is around.
void RegisterPrintBackendServiceManagerClient();
void UnregisterPrintBackendServiceManagerClient();
#endif // BUILDFLAG(ENABLE_OOP_PRINTING)
WEB_UI_CONTROLLER_TYPE_DECL();
base::TimeTicks initial_preview_start_time_;
// Tracks if this is the first instance created since the browser started.
const bool first_print_usage_since_startup_;
// The unique ID for this class instance. Stored here to avoid calling
// GetIDForPrintPreviewUI() everywhere.
std::optional<int32_t> id_;
#if BUILDFLAG(ENABLE_OOP_PRINTING)
// This UI's client ID with the print backend service manager.
PrintBackendServiceManager::ClientId service_manager_client_id_;
#endif
// Weak pointer to the WebUI handler.
const raw_ptr<PrintPreviewHandler> handler_;
// Keeps track of whether OnClosePrintPreviewDialog() has been called or not.
bool dialog_closed_ = false;
// Store the initiator title, used for populating the print preview dialog
// title.
std::u16string initiator_title_;
// The list of 0-based page indices that will be rendered.
std::vector<uint32_t> pages_to_render_;
// The list of pages to be converted.
std::vector<base::ReadOnlySharedMemoryRegion> pages_for_nup_convert_;
// Index into `pages_to_render_`. The expected page index is the value at
// `pages_to_render_[pages_to_render_index_]`
size_t pages_to_render_index_ = 0;
// number of pages per sheet and should be greater or equal to 1.
int pages_per_sheet_ = 1;
// Physical size of the page, including non-printable margins.
gfx::Size page_size_;
// The printable area of the printed document pages.
gfx::Rect printable_area_;
mojo::AssociatedReceiver<mojom::PrintPreviewUI> receiver_{this};
base::WeakPtrFactory<PrintPreviewUI> weak_ptr_factory_{this};
};
} // namespace printing
#endif // CHROME_BROWSER_UI_WEBUI_PRINT_PREVIEW_PRINT_PREVIEW_UI_H_