1 // Copyright (c) 2011 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 "chrome/browser/printing/printing_message_filter.h"
6
7 #include "base/process_util.h"
8 #include "chrome/browser/browser_process.h"
9 #include "chrome/browser/printing/printer_query.h"
10 #include "chrome/browser/printing/print_job_manager.h"
11 #include "chrome/common/print_messages.h"
12 #include "content/common/view_messages.h"
13
14 #if defined(OS_CHROMEOS)
15 #include <fcntl.h>
16
17 #include "base/file_util.h"
18 #include "base/lazy_instance.h"
19 #include "chrome/browser/printing/print_dialog_cloud.h"
20 #else
21 #include "base/command_line.h"
22 #include "chrome/common/chrome_switches.h"
23 #endif
24
25 namespace {
26
27 #if defined(OS_CHROMEOS)
28 typedef std::map<int, FilePath> SequenceToPathMap;
29
30 struct PrintingSequencePathMap {
31 SequenceToPathMap map;
32 int sequence;
33 };
34
35 // No locking, only access on the FILE thread.
36 static base::LazyInstance<PrintingSequencePathMap>
37 g_printing_file_descriptor_map(base::LINKER_INITIALIZED);
38 #endif
39
RenderParamsFromPrintSettings(const printing::PrintSettings & settings,PrintMsg_Print_Params * params)40 void RenderParamsFromPrintSettings(const printing::PrintSettings& settings,
41 PrintMsg_Print_Params* params) {
42 params->page_size = settings.page_setup_device_units().physical_size();
43 params->printable_size.SetSize(
44 settings.page_setup_device_units().content_area().width(),
45 settings.page_setup_device_units().content_area().height());
46 params->margin_top = settings.page_setup_device_units().content_area().x();
47 params->margin_left = settings.page_setup_device_units().content_area().y();
48 params->dpi = settings.dpi();
49 // Currently hardcoded at 1.25. See PrintSettings' constructor.
50 params->min_shrink = settings.min_shrink;
51 // Currently hardcoded at 2.0. See PrintSettings' constructor.
52 params->max_shrink = settings.max_shrink;
53 // Currently hardcoded at 72dpi. See PrintSettings' constructor.
54 params->desired_dpi = settings.desired_dpi;
55 // Always use an invalid cookie.
56 params->document_cookie = 0;
57 params->selection_only = settings.selection_only;
58 params->supports_alpha_blend = settings.supports_alpha_blend();
59 }
60
61 } // namespace
62
PrintingMessageFilter()63 PrintingMessageFilter::PrintingMessageFilter()
64 : print_job_manager_(g_browser_process->print_job_manager()) {
65 #if defined(OS_CHROMEOS)
66 cloud_print_enabled_ = true;
67 #else
68 cloud_print_enabled_ = CommandLine::ForCurrentProcess()->HasSwitch(
69 switches::kEnableCloudPrint);
70 #endif
71 }
72
~PrintingMessageFilter()73 PrintingMessageFilter::~PrintingMessageFilter() {
74 }
75
OverrideThreadForMessage(const IPC::Message & message,BrowserThread::ID * thread)76 void PrintingMessageFilter::OverrideThreadForMessage(
77 const IPC::Message& message, BrowserThread::ID* thread) {
78 #if defined(OS_CHROMEOS)
79 if (message.type() == PrintHostMsg_AllocateTempFileForPrinting::ID ||
80 message.type() == PrintHostMsg_TempFileForPrintingWritten::ID) {
81 *thread = BrowserThread::FILE;
82 }
83 #endif
84 }
85
OnMessageReceived(const IPC::Message & message,bool * message_was_ok)86 bool PrintingMessageFilter::OnMessageReceived(const IPC::Message& message,
87 bool* message_was_ok) {
88 bool handled = true;
89 IPC_BEGIN_MESSAGE_MAP_EX(PrintingMessageFilter, message, *message_was_ok)
90 #if defined(OS_WIN)
91 IPC_MESSAGE_HANDLER(PrintHostMsg_DuplicateSection, OnDuplicateSection)
92 #endif
93 #if defined(OS_CHROMEOS)
94 IPC_MESSAGE_HANDLER(PrintHostMsg_AllocateTempFileForPrinting,
95 OnAllocateTempFileForPrinting)
96 IPC_MESSAGE_HANDLER(PrintHostMsg_TempFileForPrintingWritten,
97 OnTempFileForPrintingWritten)
98 #endif
99 IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_GetDefaultPrintSettings,
100 OnGetDefaultPrintSettings)
101 IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_ScriptedPrint, OnScriptedPrint)
102 IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_UpdatePrintSettings,
103 OnUpdatePrintSettings)
104 IPC_MESSAGE_UNHANDLED(handled = false)
105 IPC_END_MESSAGE_MAP()
106 return handled;
107 }
108
109 #if defined(OS_WIN)
OnDuplicateSection(base::SharedMemoryHandle renderer_handle,base::SharedMemoryHandle * browser_handle)110 void PrintingMessageFilter::OnDuplicateSection(
111 base::SharedMemoryHandle renderer_handle,
112 base::SharedMemoryHandle* browser_handle) {
113 // Duplicate the handle in this process right now so the memory is kept alive
114 // (even if it is not mapped)
115 base::SharedMemory shared_buf(renderer_handle, true, peer_handle());
116 shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), browser_handle);
117 }
118 #endif
119
120 #if defined(OS_CHROMEOS)
OnAllocateTempFileForPrinting(base::FileDescriptor * temp_file_fd,int * sequence_number)121 void PrintingMessageFilter::OnAllocateTempFileForPrinting(
122 base::FileDescriptor* temp_file_fd, int* sequence_number) {
123 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
124 temp_file_fd->fd = *sequence_number = -1;
125 temp_file_fd->auto_close = false;
126
127 SequenceToPathMap* map = &g_printing_file_descriptor_map.Get().map;
128 *sequence_number = g_printing_file_descriptor_map.Get().sequence++;
129
130 FilePath path;
131 if (file_util::CreateTemporaryFile(&path)) {
132 int fd = open(path.value().c_str(), O_WRONLY);
133 if (fd >= 0) {
134 SequenceToPathMap::iterator it = map->find(*sequence_number);
135 if (it != map->end()) {
136 NOTREACHED() << "Sequence number already in use. seq=" <<
137 *sequence_number;
138 } else {
139 (*map)[*sequence_number] = path;
140 temp_file_fd->fd = fd;
141 temp_file_fd->auto_close = true;
142 }
143 }
144 }
145 }
146
OnTempFileForPrintingWritten(int sequence_number)147 void PrintingMessageFilter::OnTempFileForPrintingWritten(int sequence_number) {
148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
149 SequenceToPathMap* map = &g_printing_file_descriptor_map.Get().map;
150 SequenceToPathMap::iterator it = map->find(sequence_number);
151 if (it == map->end()) {
152 NOTREACHED() << "Got a sequence that we didn't pass to the "
153 "renderer: " << sequence_number;
154 return;
155 }
156
157 if (cloud_print_enabled_)
158 print_dialog_cloud::CreatePrintDialogForFile(
159 it->second,
160 string16(),
161 std::string("application/pdf"),
162 true);
163 else
164 NOTIMPLEMENTED();
165
166 // Erase the entry in the map.
167 map->erase(it);
168 }
169 #endif // defined(OS_CHROMEOS)
170
OnGetDefaultPrintSettings(IPC::Message * reply_msg)171 void PrintingMessageFilter::OnGetDefaultPrintSettings(IPC::Message* reply_msg) {
172 scoped_refptr<printing::PrinterQuery> printer_query;
173 if (!print_job_manager_->printing_enabled()) {
174 // Reply with NULL query.
175 OnGetDefaultPrintSettingsReply(printer_query, reply_msg);
176 return;
177 }
178
179 print_job_manager_->PopPrinterQuery(0, &printer_query);
180 if (!printer_query.get()) {
181 printer_query = new printing::PrinterQuery;
182 }
183
184 CancelableTask* task = NewRunnableMethod(
185 this,
186 &PrintingMessageFilter::OnGetDefaultPrintSettingsReply,
187 printer_query,
188 reply_msg);
189 // Loads default settings. This is asynchronous, only the IPC message sender
190 // will hang until the settings are retrieved.
191 printer_query->GetSettings(printing::PrinterQuery::DEFAULTS,
192 NULL,
193 0,
194 false,
195 true,
196 task);
197 }
198
OnGetDefaultPrintSettingsReply(scoped_refptr<printing::PrinterQuery> printer_query,IPC::Message * reply_msg)199 void PrintingMessageFilter::OnGetDefaultPrintSettingsReply(
200 scoped_refptr<printing::PrinterQuery> printer_query,
201 IPC::Message* reply_msg) {
202 PrintMsg_Print_Params params;
203 if (!printer_query.get() ||
204 printer_query->last_status() != printing::PrintingContext::OK) {
205 memset(¶ms, 0, sizeof(params));
206 } else {
207 RenderParamsFromPrintSettings(printer_query->settings(), ¶ms);
208 params.document_cookie = printer_query->cookie();
209 }
210 PrintHostMsg_GetDefaultPrintSettings::WriteReplyParams(reply_msg, params);
211 Send(reply_msg);
212 // If printing was enabled.
213 if (printer_query.get()) {
214 // If user hasn't cancelled.
215 if (printer_query->cookie() && printer_query->settings().dpi()) {
216 print_job_manager_->QueuePrinterQuery(printer_query.get());
217 } else {
218 printer_query->StopWorker();
219 }
220 }
221 }
222
OnScriptedPrint(const PrintHostMsg_ScriptedPrint_Params & params,IPC::Message * reply_msg)223 void PrintingMessageFilter::OnScriptedPrint(
224 const PrintHostMsg_ScriptedPrint_Params& params,
225 IPC::Message* reply_msg) {
226 gfx::NativeView host_view =
227 gfx::NativeViewFromIdInBrowser(params.host_window_id);
228
229 scoped_refptr<printing::PrinterQuery> printer_query;
230 print_job_manager_->PopPrinterQuery(params.cookie, &printer_query);
231 if (!printer_query.get()) {
232 printer_query = new printing::PrinterQuery;
233 }
234
235 CancelableTask* task = NewRunnableMethod(
236 this,
237 &PrintingMessageFilter::OnScriptedPrintReply,
238 printer_query,
239 params.routing_id,
240 reply_msg);
241
242 printer_query->GetSettings(printing::PrinterQuery::ASK_USER,
243 host_view,
244 params.expected_pages_count,
245 params.has_selection,
246 params.use_overlays,
247 task);
248 }
249
OnScriptedPrintReply(scoped_refptr<printing::PrinterQuery> printer_query,int routing_id,IPC::Message * reply_msg)250 void PrintingMessageFilter::OnScriptedPrintReply(
251 scoped_refptr<printing::PrinterQuery> printer_query,
252 int routing_id,
253 IPC::Message* reply_msg) {
254 PrintMsg_PrintPages_Params params;
255 if (printer_query->last_status() != printing::PrintingContext::OK ||
256 !printer_query->settings().dpi()) {
257 memset(¶ms, 0, sizeof(params));
258 } else {
259 RenderParamsFromPrintSettings(printer_query->settings(), ¶ms.params);
260 params.params.document_cookie = printer_query->cookie();
261 params.pages =
262 printing::PageRange::GetPages(printer_query->settings().ranges);
263 }
264 PrintHostMsg_ScriptedPrint::WriteReplyParams(reply_msg, params);
265 Send(reply_msg);
266 if (params.params.dpi && params.params.document_cookie) {
267 print_job_manager_->QueuePrinterQuery(printer_query.get());
268 } else {
269 printer_query->StopWorker();
270 }
271 }
272
OnUpdatePrintSettings(int document_cookie,const DictionaryValue & job_settings,IPC::Message * reply_msg)273 void PrintingMessageFilter::OnUpdatePrintSettings(
274 int document_cookie, const DictionaryValue& job_settings,
275 IPC::Message* reply_msg) {
276 scoped_refptr<printing::PrinterQuery> printer_query;
277 print_job_manager_->PopPrinterQuery(document_cookie, &printer_query);
278 if (printer_query.get()) {
279 CancelableTask* task = NewRunnableMethod(
280 this,
281 &PrintingMessageFilter::OnUpdatePrintSettingsReply,
282 printer_query,
283 reply_msg);
284 printer_query->SetSettings(job_settings, task);
285 }
286 }
287
OnUpdatePrintSettingsReply(scoped_refptr<printing::PrinterQuery> printer_query,IPC::Message * reply_msg)288 void PrintingMessageFilter::OnUpdatePrintSettingsReply(
289 scoped_refptr<printing::PrinterQuery> printer_query,
290 IPC::Message* reply_msg) {
291 PrintMsg_PrintPages_Params params;
292 if (printer_query->last_status() != printing::PrintingContext::OK) {
293 memset(¶ms, 0, sizeof(params));
294 } else {
295 RenderParamsFromPrintSettings(printer_query->settings(), ¶ms.params);
296 params.params.document_cookie = printer_query->cookie();
297 params.pages =
298 printing::PageRange::GetPages(printer_query->settings().ranges);
299 }
300 PrintHostMsg_UpdatePrintSettings::WriteReplyParams(reply_msg, params);
301 Send(reply_msg);
302 // If user hasn't cancelled.
303 if (printer_query->cookie() && printer_query->settings().dpi())
304 print_job_manager_->QueuePrinterQuery(printer_query.get());
305 else
306 printer_query->StopWorker();
307 }
308