1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/printing/browser/print_manager.h"
6 
7 #include "base/bind.h"
8 #include "build/build_config.h"
9 #include "components/printing/common/print_messages.h"
10 #include "content/public/browser/render_frame_host.h"
11 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
12 
13 namespace printing {
14 
15 struct PrintManager::FrameDispatchHelper {
16   PrintManager* manager;
17   content::RenderFrameHost* render_frame_host;
18 
Sendprinting::PrintManager::FrameDispatchHelper19   bool Send(IPC::Message* msg) { return render_frame_host->Send(msg); }
20 
OnGetDefaultPrintSettingsprinting::PrintManager::FrameDispatchHelper21   void OnGetDefaultPrintSettings(IPC::Message* reply_msg) {
22     manager->OnGetDefaultPrintSettings(render_frame_host, reply_msg);
23   }
24 
OnScriptedPrintprinting::PrintManager::FrameDispatchHelper25   void OnScriptedPrint(const PrintHostMsg_ScriptedPrint_Params& scripted_params,
26                        IPC::Message* reply_msg) {
27     manager->OnScriptedPrint(render_frame_host, scripted_params, reply_msg);
28   }
29 
OnDidPrintDocumentprinting::PrintManager::FrameDispatchHelper30   void OnDidPrintDocument(const PrintHostMsg_DidPrintDocument_Params& params,
31                           IPC::Message* reply_msg) {
32     // If DidPrintDocument message was received then need to transition from
33     // a variable allocated on stack (which has efficient memory management
34     // when dealing with any other incoming message) to a persistent variable
35     // on the heap that can be referenced by the asynchronous processing which
36     // occurs beyond the scope of PrintViewManagerBase::OnMessageReceived().
37     manager->OnDidPrintDocument(
38         render_frame_host, params,
39         std::make_unique<DelayedFrameDispatchHelper>(
40             manager->web_contents(), render_frame_host, reply_msg));
41   }
42 };
43 
DelayedFrameDispatchHelper(content::WebContents * contents,content::RenderFrameHost * render_frame_host,IPC::Message * reply_msg)44 PrintManager::DelayedFrameDispatchHelper::DelayedFrameDispatchHelper(
45     content::WebContents* contents,
46     content::RenderFrameHost* render_frame_host,
47     IPC::Message* reply_msg)
48     : content::WebContentsObserver(contents),
49       render_frame_host_(render_frame_host),
50       reply_msg_(reply_msg) {}
51 
~DelayedFrameDispatchHelper()52 PrintManager::DelayedFrameDispatchHelper::~DelayedFrameDispatchHelper() {
53   if (reply_msg_) {
54     PrintHostMsg_DidPrintDocument::WriteReplyParams(reply_msg_, false);
55     render_frame_host_->Send(reply_msg_);
56   }
57 }
58 
SendCompleted()59 void PrintManager::DelayedFrameDispatchHelper::SendCompleted() {
60   if (!reply_msg_)
61     return;
62 
63   PrintHostMsg_DidPrintDocument::WriteReplyParams(reply_msg_, true);
64   render_frame_host_->Send(reply_msg_);
65 
66   // This wraps up the one allowed reply for the message.
67   reply_msg_ = nullptr;
68 }
69 
RenderFrameDeleted(content::RenderFrameHost * render_frame_host)70 void PrintManager::DelayedFrameDispatchHelper::RenderFrameDeleted(
71     content::RenderFrameHost* render_frame_host) {
72   if (render_frame_host == render_frame_host_)
73     reply_msg_ = nullptr;
74 }
75 
PrintManager(content::WebContents * contents)76 PrintManager::PrintManager(content::WebContents* contents)
77     : content::WebContentsObserver(contents) {}
78 
79 PrintManager::~PrintManager() = default;
80 
OnMessageReceived(const IPC::Message & message,content::RenderFrameHost * render_frame_host)81 bool PrintManager::OnMessageReceived(
82     const IPC::Message& message,
83     content::RenderFrameHost* render_frame_host) {
84   FrameDispatchHelper helper = {this, render_frame_host};
85   bool handled = true;
86   IPC_BEGIN_MESSAGE_MAP(PrintManager, message)
87     IPC_MESSAGE_HANDLER(PrintHostMsg_DidGetPrintedPagesCount,
88                         OnDidGetPrintedPagesCount)
89     IPC_MESSAGE_HANDLER(PrintHostMsg_DidGetDocumentCookie,
90                         OnDidGetDocumentCookie)
91     IPC_MESSAGE_FORWARD_DELAY_REPLY(
92         PrintHostMsg_GetDefaultPrintSettings, &helper,
93         FrameDispatchHelper::OnGetDefaultPrintSettings)
94     IPC_MESSAGE_FORWARD_DELAY_REPLY(PrintHostMsg_ScriptedPrint, &helper,
95                                     FrameDispatchHelper::OnScriptedPrint)
96     IPC_MESSAGE_FORWARD_DELAY_REPLY(PrintHostMsg_DidPrintDocument, &helper,
97                                     FrameDispatchHelper::OnDidPrintDocument);
98 
99     IPC_MESSAGE_HANDLER(PrintHostMsg_PrintingFailed, OnPrintingFailed)
100     IPC_MESSAGE_UNHANDLED(handled = false)
101   IPC_END_MESSAGE_MAP()
102   return handled;
103 }
104 
RenderFrameDeleted(content::RenderFrameHost * render_frame_host)105 void PrintManager::RenderFrameDeleted(
106     content::RenderFrameHost* render_frame_host) {
107   print_render_frames_.erase(render_frame_host);
108 }
109 
OnDidGetPrintedPagesCount(int cookie,int number_pages)110 void PrintManager::OnDidGetPrintedPagesCount(int cookie,
111                                              int number_pages) {
112   DCHECK_GT(cookie, 0);
113   DCHECK_GT(number_pages, 0);
114   number_pages_ = number_pages;
115 }
116 
OnDidGetDocumentCookie(int cookie)117 void PrintManager::OnDidGetDocumentCookie(int cookie) {
118   cookie_ = cookie;
119 }
120 
OnPrintingFailed(int cookie)121 void PrintManager::OnPrintingFailed(int cookie) {
122   if (cookie != cookie_) {
123     NOTREACHED();
124     return;
125   }
126 #if defined(OS_ANDROID)
127   PdfWritingDone(0);
128 #endif
129 }
130 
131 const mojo::AssociatedRemote<printing::mojom::PrintRenderFrame>&
GetPrintRenderFrame(content::RenderFrameHost * rfh)132 PrintManager::GetPrintRenderFrame(content::RenderFrameHost* rfh) {
133   auto it = print_render_frames_.find(rfh);
134   if (it == print_render_frames_.end()) {
135     mojo::AssociatedRemote<printing::mojom::PrintRenderFrame> remote;
136     rfh->GetRemoteAssociatedInterfaces()->GetInterface(&remote);
137     it = print_render_frames_.insert(std::make_pair(rfh, std::move(remote))).first;
138   } else if (it->second.is_bound() && !it->second.is_connected()) {
139     // When print preview is closed, the remote is disconnected from the
140     // receiver. Reset and bind the remote before using it again.
141     it->second.reset();
142     rfh->GetRemoteAssociatedInterfaces()->GetInterface(&it->second);
143   }
144 
145   return it->second;
146 }
147 
PrintingRenderFrameDeleted()148 void PrintManager::PrintingRenderFrameDeleted() {
149 #if defined(OS_ANDROID)
150   PdfWritingDone(0);
151 #endif
152 }
153 
154 }  // namespace printing
155