Commit d9b3351f authored by Julie Jeongeun Kim's avatar Julie Jeongeun Kim Committed by Chromium LUCI CQ

[printing] Queue the sub frame if the compositor is not created

OnDidPrintFrameContent() by the sub frame should be handled after
the compositor for the main frame is created but it could handled
before the main frame. This CL queues the sub frame if the
compositor is not created and handles the queue after the
compositor is created.

Bug:1152971

Change-Id: I841247bcc6a1dcfc6c019613edbbeab3e177c8be
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2559476
Commit-Queue: Julie Kim <jkim@igalia.com>
Reviewed-by: default avatarWei Li <weili@chromium.org>
Cr-Commit-Position: refs/heads/master@{#833634}
parent fd8ea126
......@@ -209,8 +209,8 @@ class TestPrintRenderFrame
EXPECT_EQ(document_cookie, document_cookie_);
ASSERT_TRUE(param->metafile_data_region.IsValid());
EXPECT_GT(param->metafile_data_region.GetSize(), 0U);
task_runner_->PostTask(FROM_HERE, msg_callback_);
std::move(callback).Run(document_cookie, std::move(param));
task_runner_->PostTask(FROM_HERE, msg_callback_);
}
void Bind(mojo::ScopedInterfaceEndpointHandle handle) {
......@@ -218,6 +218,17 @@ class TestPrintRenderFrame
std::move(handle)));
}
static mojom::DidPrintContentParamsPtr GetDefaultDidPrintContentParams() {
auto printed_frame_params = mojom::DidPrintContentParams::New();
// Creates a small amount of region to avoid passing empty data to mojo.
constexpr size_t kSize = 10;
base::MappedReadOnlyRegion region_mapping =
base::ReadOnlySharedMemoryRegion::Create(kSize);
printed_frame_params->metafile_data_region =
std::move(region_mapping.region);
return printed_frame_params;
}
// mojom::PrintRenderFrameInterceptorForTesting
mojom::PrintRenderFrame* GetForwardingInterface() override {
NOTREACHED();
......@@ -226,16 +237,8 @@ class TestPrintRenderFrame
void PrintFrameContent(mojom::PrintFrameContentParamsPtr params,
PrintFrameContentCallback callback) override {
// Sends the printed result back.
mojom::DidPrintContentParamsPtr printed_frame_params =
mojom::DidPrintContentParams::New();
// Creates a small amount of region to avoid passing empty data to mojo.
constexpr size_t kSize = 10;
base::MappedReadOnlyRegion region_mapping =
base::ReadOnlySharedMemoryRegion::Create(kSize);
printed_frame_params->metafile_data_region =
std::move(region_mapping.region);
OnDidPrintFrameContent(params->document_cookie,
std::move(printed_frame_params),
GetDefaultDidPrintContentParams(),
std::move(callback));
auto* client = PrintCompositeClient::FromWebContents(web_contents_);
......@@ -814,6 +817,70 @@ IN_PROC_BROWSER_TEST_F(PrintBrowserTest, PrintSubframeABA) {
WaitUntilCallbackReceived();
}
// Printing frame content with a cross-site iframe before creating
// PrintCompositor by the main frame.
// This test passes if PrintCompositeClient queues subframes when
// it doesn't have PrintCompositor and clears them after PrintCompositor is
// created.
IN_PROC_BROWSER_TEST_F(PrintBrowserTest,
PrintSubframeContentBeforeCompositeClientCreation) {
ASSERT_TRUE(embedded_test_server()->Started());
GURL url(
embedded_test_server()->GetURL("/printing/content_with_iframe.html"));
ui_test_utils::NavigateToURL(browser(), url);
// When OOPIF is not enabled, CompositorClient is not used.
if (!IsOopifEnabled())
return;
content::WebContents* original_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_EQ(2u, original_contents->GetAllFrames().size());
content::RenderFrameHost* main_frame = original_contents->GetMainFrame();
ASSERT_TRUE(main_frame);
content::RenderFrameHost* test_frame = original_contents->GetAllFrames()[1];
ASSERT_TRUE(test_frame);
ASSERT_NE(main_frame->GetProcess(), test_frame->GetProcess());
CreateTestPrintRenderFrame(main_frame, original_contents);
CreateTestPrintRenderFrame(test_frame, original_contents);
SetNumExpectedMessages(2);
// Print on the main frame.
GetPrintRenderFrame(main_frame)
->PrintFrameContent(GetDefaultPrintFrameParams(), base::DoNothing());
// The printed result will be received and checked in TestPrintRenderFrame.
WaitUntilCallbackReceived();
// As PrintFrameContent() with the main frame doesn't call
// PrintCompositeClient::DoCompositeDocumentToPdf() on this test, when
// PrintCompositeClient::OnDidPrintFrameContent() is called with the sub
// frame, it doesn't have mojom::PrintCompositor.
auto* client = PrintCompositeClient::FromWebContents(original_contents);
ASSERT_FALSE(client->compositor_);
// When there is no mojom::PrintCompositor, PrintCompositeClient queues
// subframes and handles them when mojom::PrintCompositor is created.
// |requested_subframes_| should have the requested subframes.
ASSERT_EQ(1u, client->requested_subframes_.size());
PrintCompositeClient::RequestedSubFrame* subframe_in_queue =
client->requested_subframes_.begin()->get();
ASSERT_EQ(kDefaultDocumentCookie, subframe_in_queue->document_cookie_);
ASSERT_EQ(test_frame->GetProcess()->GetID(),
subframe_in_queue->render_process_id_);
ASSERT_EQ(test_frame->GetRoutingID(), subframe_in_queue->render_frame_id_);
// Creates mojom::PrintCompositor.
client->DoCompositeDocumentToPdf(
kDefaultDocumentCookie, main_frame,
*TestPrintRenderFrame::GetDefaultDidPrintContentParams(),
base::DoNothing());
ASSERT_TRUE(client->GetCompositeRequest(kDefaultDocumentCookie));
// |requested_subframes_| should be empty.
ASSERT_TRUE(client->requested_subframes_.empty());
}
// Printing preview a simple webpage when site per process is enabled.
// Test that the basic oopif printing should succeed. The test should not crash
// or timed out. There could be other reasons that cause the test fail, but the
......
......@@ -101,6 +101,19 @@ void PrintCompositeClient::RenderFrameDeleted(
print_render_frames_.erase(render_frame_host);
}
PrintCompositeClient::RequestedSubFrame::RequestedSubFrame(
int render_process_id,
int render_frame_id,
int document_cookie,
mojom::DidPrintContentParamsPtr params,
bool is_live)
: render_process_id_(render_process_id),
render_frame_id_(render_frame_id),
document_cookie_(document_cookie),
params_(std::move(params)),
is_live_(is_live) {}
PrintCompositeClient::RequestedSubFrame::~RequestedSubFrame() = default;
void PrintCompositeClient::OnDidPrintFrameContent(
int render_process_id,
int render_frame_id,
......@@ -121,8 +134,16 @@ void PrintCompositeClient::OnDidPrintFrameContent(
return;
}
if (!IsDocumentCookieValid(document_cookie))
if (!IsDocumentCookieValid(document_cookie)) {
if (!compositor_) {
// Queues the subframe information to |requested_subframes_| to handle it
// after |compositor_| is created by the main frame.
requested_subframes_.insert(std::make_unique<RequestedSubFrame>(
render_process_id, render_frame_id, document_cookie,
std::move(params), true));
}
return;
}
auto* render_frame_host =
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
......@@ -161,8 +182,16 @@ void PrintCompositeClient::PrintCrossProcessSubframe(
content::RenderFrameHost* subframe_host) {
auto params = mojom::PrintFrameContentParams::New(rect, document_cookie);
if (!subframe_host->IsRenderFrameLive()) {
if (!IsDocumentCookieValid(document_cookie))
if (!IsDocumentCookieValid(document_cookie)) {
if (!compositor_) {
// Queues the subframe information to |requested_subframes_| to handle
// it after |compositor_| is created by the main frame.
requested_subframes_.insert(std::make_unique<RequestedSubFrame>(
subframe_host->GetProcess()->GetID(), subframe_host->GetRoutingID(),
document_cookie, nullptr, false));
}
return;
}
// When the subframe is dead, no need to send message,
// just notify the service.
......@@ -178,14 +207,13 @@ void PrintCompositeClient::PrintCrossProcessSubframe(
}
// Send the request to the destination frame.
int render_process_id = subframe_host->GetProcess()->GetID();
int render_frame_id = subframe_host->GetRoutingID();
GetPrintRenderFrame(subframe_host)
->PrintFrameContent(
std::move(params),
base::BindOnce(&PrintCompositeClient::OnDidPrintFrameContent,
weak_ptr_factory_.GetWeakPtr(), render_process_id,
render_frame_id));
weak_ptr_factory_.GetWeakPtr(),
subframe_host->GetProcess()->GetID(),
subframe_host->GetRoutingID()));
pending_subframes_.insert(subframe_host);
}
......@@ -253,6 +281,23 @@ void PrintCompositeClient::DoCompositeDocumentToPdf(
DCHECK(!GetIsDocumentConcurrentlyComposited(document_cookie));
auto* compositor = CreateCompositeRequest(document_cookie, render_frame_host);
for (auto& requested : requested_subframes_) {
if (!IsDocumentCookieValid(requested->document_cookie_))
continue;
if (requested->is_live_) {
OnDidPrintFrameContent(
requested->render_process_id_, requested->render_frame_id_,
requested->document_cookie_, std::move(requested->params_));
} else {
auto* render_frame_host = content::RenderFrameHost::FromID(
requested->render_process_id_, requested->render_frame_id_);
compositor->NotifyUnavailableSubframe(
GenerateFrameGuid(render_frame_host));
}
}
requested_subframes_.clear();
auto region = content.metafile_data_region.Duplicate();
// Since this class owns compositor, compositor will be gone when this class
......
......@@ -94,6 +94,9 @@ class PrintCompositeClient
private:
friend class content::WebContentsUserData<PrintCompositeClient>;
FRIEND_TEST_ALL_PREFIXES(PrintBrowserTest,
PrintSubframeContentBeforeCompositeClientCreation);
// Callback functions for getting the replies.
static void OnDidCompositePageToPdf(
mojom::PrintCompositor::CompositePageToPdfCallback callback,
......@@ -167,6 +170,25 @@ class PrintCompositeClient
// Stores the printed subframes for the composited document.
base::flat_set<content::RenderFrameHost*> printed_subframes_;
struct RequestedSubFrame {
RequestedSubFrame(int render_process_id,
int render_frame_id,
int document_cookie,
mojom::DidPrintContentParamsPtr params,
bool is_live);
~RequestedSubFrame();
RequestedSubFrame(const PrintCompositeClient::RequestedSubFrame&) = delete;
RequestedSubFrame& operator=(
const PrintCompositeClient::RequestedSubFrame&) = delete;
int render_process_id_;
int render_frame_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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment