blob: 5c74517d81c8502077189b857b7e1de717f25e91 [file] [log] [blame]
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_PRINTING_BROWSER_PRINT_COMPOSITE_CLIENT_H_
#define COMPONENTS_PRINTING_BROWSER_PRINT_COMPOSITE_CLIENT_H_
#include <map>
#include <memory>
#include "base/containers/flat_set.h"
#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "build/build_config.h"
#include "components/printing/common/print.mojom.h"
#include "components/services/print_compositor/public/mojom/print_compositor.mojom.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "mojo/public/cpp/bindings/associated_remote.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "printing/buildflags/buildflags.h"
#include "printing/mojom/print.mojom.h"
#include "ui/accessibility/ax_tree_update_forward.h"
namespace printing {
// Class to manage print requests and their communication with print compositor
// service. Each composite request have a separate interface pointer to connect
// with remote service. The request and its subframe printing results are
// tracked by its document cookie and print page number.
class PrintCompositeClient
: public content::WebContentsUserData<PrintCompositeClient>,
public content::WebContentsObserver {
public:
explicit PrintCompositeClient(content::WebContents* web_contents);
PrintCompositeClient(const PrintCompositeClient&) = delete;
PrintCompositeClient& operator=(const PrintCompositeClient&) = delete;
~PrintCompositeClient() override;
// content::WebContentsObserver
void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override;
void SetAccessibilityTree(int document_cookie,
const ui::AXTreeUpdate& accessibility_tree);
// Instructs the specified subframe to print.
void PrintCrossProcessSubframe(const gfx::Rect& rect,
int document_cookie,
content::RenderFrameHost* subframe_host);
// Printing single pages is only used by print preview for early return of
// rendered results. In this case, the pages share the content with printed
// document. The document can be collected from the individual pages,
// avoiding the need to also send the entire document again as a large blob.
// This is for compositing such a single preview page.
void CompositePage(int cookie,
content::RenderFrameHost* render_frame_host,
const mojom::DidPrintContentParams& content,
mojom::PrintCompositor::CompositePageCallback callback);
// Notifies compositor to collect individual pages into a document
// when processing the individual pages for preview. The `document_type`
// specified determines the format of the document passed back in the
// `callback` from `FinishDocumentComposition()`.
void PrepareToCompositeDocument(
int document_cookie,
content::RenderFrameHost* render_frame_host,
mojom::PrintCompositor::DocumentType document_type,
mojom::PrintCompositor::PrepareToCompositeDocumentCallback callback);
// Notifies compositor of the total number of pages being concurrently
// collected into the document, allowing for completion of the composition
// when all pages have been received. The format of the provided document
// is of the `document_type` specified in `PrepareToCompositeDocument()`.
void FinishDocumentComposition(
int document_cookie,
uint32_t pages_count,
mojom::PrintCompositor::FinishDocumentCompositionCallback callback);
// Used for compositing the entire document for print preview or actual
// printing.
void CompositeDocument(
int cookie,
content::RenderFrameHost* render_frame_host,
const mojom::DidPrintContentParams& content,
const ui::AXTreeUpdate& accessibility_tree,
mojom::GenerateDocumentOutline generate_document_outline,
mojom::PrintCompositor::DocumentType document_type,
mojom::PrintCompositor::CompositeDocumentCallback callback);
// Get the concurrent composition status for a document. Identifies if the
// full document will be compiled from the individual pages; if not then a
// separate document object will need to be provided.
bool GetIsDocumentConcurrentlyComposited(int cookie) const;
void SetUserAgent(const std::string& user_agent) { user_agent_ = user_agent; }
private:
friend class content::WebContentsUserData<PrintCompositeClient>;
FRIEND_TEST_ALL_PREFIXES(PrintBrowserTest,
PrintSubframeContentBeforeCompositeClientCreation);
// Callback functions for getting the replies.
static void OnDidCompositePage(
mojom::PrintCompositor::CompositePageCallback callback,
mojom::PrintCompositor::Status status,
base::ReadOnlySharedMemoryRegion region);
void OnDidCompositeDocument(
int document_cookie,
mojom::PrintCompositor::CompositeDocumentCallback callback,
mojom::PrintCompositor::Status status,
base::ReadOnlySharedMemoryRegion region);
static void OnDidPrepareToCompositeDocument(
mojom::PrintCompositor::PrepareToCompositeDocumentCallback callback,
mojom::PrintCompositor::Status status);
void OnDidFinishDocumentComposition(
int document_cookie,
mojom::PrintCompositor::FinishDocumentCompositionCallback callback,
mojom::PrintCompositor::Status status,
base::ReadOnlySharedMemoryRegion region);
void OnDidPrintFrameContent(content::GlobalRenderFrameHostId rfh_id,
int document_cookie,
mojom::DidPrintContentParamsPtr params);
// Creates a new composite request for a given document |cookie|. Since
// printed pages always share content with its document, they share the same
// composite request. Launches the compositor in a separate process.
// If a composite request already exists, it is removed.
// Returns the created composite request.
mojom::PrintCompositor* CreateCompositeRequest(
int cookie,
content::RenderFrameHost* initiator_frame,
mojom::PrintCompositor::DocumentType document_type);
// Remove the existing composite request.
void RemoveCompositeRequest(int cookie);
// Checks if the |document_cookie| is not 0 and matches |document_cookie_|.
bool IsDocumentCookieValid(int document_cookie) const;
// Get the composite request of a document. |cookie| must be valid and equal
// to |document_cookie_|.
mojom::PrintCompositor* GetCompositeRequest(int cookie) const;
// Helper method to fetch the PrintRenderFrame remote interface pointer
// associated with a given subframe.
const mojo::AssociatedRemote<mojom::PrintRenderFrame>& GetPrintRenderFrame(
content::RenderFrameHost* rfh);
// Stores the message pipe endpoint for making remote calls to the compositor.
mojo::Remote<mojom::PrintCompositor> compositor_;
// Stores the unique sequential cookie of the document being composited.
// Holds 0 if no document is being composited.
int document_cookie_ = 0;
// Stores whether the document is concurrently compositing using individual
// pages, so that no separate composite request with full-document blob is
// required.
bool is_doc_concurrently_composited_ = false;
// Stores the the frame that initiated the composite request;
// Holds nullptr if no document is being composited.
raw_ptr<content::RenderFrameHost> initiator_frame_ = nullptr;
// Stores the pending subframes for the composited document.
base::flat_set<raw_ptr<content::RenderFrameHost, CtnExperimental>>
pending_subframes_;
// Stores the printed subframes for the composited document.
base::flat_set<raw_ptr<content::RenderFrameHost, CtnExperimental>>
printed_subframes_;
struct RequestedSubFrame {
RequestedSubFrame(content::GlobalRenderFrameHostId rfh_id,
int document_cookie,
mojom::DidPrintContentParamsPtr params,
bool is_live);
~RequestedSubFrame();
RequestedSubFrame(const RequestedSubFrame&) = delete;
RequestedSubFrame& operator=(const RequestedSubFrame&) = delete;
content::GlobalRenderFrameHostId rfh_id_;
int document_cookie_;
mojom::DidPrintContentParamsPtr params_;
bool is_live_;
};
base::flat_set<std::unique_ptr<RequestedSubFrame>> requested_subframes_;
std::string user_agent_;
// Stores a PrintRenderFrame associated remote with the RenderFrameHost used
// to bind it. The PrintRenderFrame is used to transmit mojo interface method
// calls to the associated receiver.
std::map<content::RenderFrameHost*,
mojo::AssociatedRemote<mojom::PrintRenderFrame>>
print_render_frames_;
base::WeakPtrFactory<PrintCompositeClient> weak_ptr_factory_{this};
WEB_CONTENTS_USER_DATA_KEY_DECL();
};
} // namespace printing
#endif // COMPONENTS_PRINTING_BROWSER_PRINT_COMPOSITE_CLIENT_H_