Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / printing / printing_message_filter.cc
1 // Copyright (c) 2012 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 <string>
8
9 #include "base/bind.h"
10 #include "chrome/browser/browser_process.h"
11 #include "chrome/browser/printing/printer_query.h"
12 #include "chrome/browser/printing/print_job_manager.h"
13 #include "chrome/browser/printing/printing_ui_web_contents_observer.h"
14 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/profiles/profile_io_data.h"
16 #include "chrome/common/print_messages.h"
17 #include "content/public/browser/browser_thread.h"
18 #include "content/public/browser/render_view_host.h"
19 #include "content/public/browser/web_contents.h"
20
21 #if defined(ENABLE_FULL_PRINTING)
22 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
23 #endif
24
25 #if defined(OS_CHROMEOS)
26 #include <fcntl.h>
27
28 #include <map>
29
30 #include "base/file_util.h"
31 #include "base/lazy_instance.h"
32 #include "chrome/browser/printing/print_dialog_cloud.h"
33 #include "content/public/browser/web_contents_view.h"
34 #endif
35
36 #if defined(OS_ANDROID)
37 #include "base/strings/string_number_conversions.h"
38 #include "chrome/browser/printing/print_view_manager_basic.h"
39 #include "printing/printing_context_android.h"
40 #endif
41
42 using content::BrowserThread;
43
44 namespace {
45
46 #if defined(OS_CHROMEOS)
47 typedef std::map<int, base::FilePath> SequenceToPathMap;
48
49 struct PrintingSequencePathMap {
50   SequenceToPathMap map;
51   int sequence;
52 };
53
54 // No locking, only access on the FILE thread.
55 static base::LazyInstance<PrintingSequencePathMap>
56     g_printing_file_descriptor_map = LAZY_INSTANCE_INITIALIZER;
57 #endif
58
59 void RenderParamsFromPrintSettings(const printing::PrintSettings& settings,
60                                    PrintMsg_Print_Params* params) {
61   params->page_size = settings.page_setup_device_units().physical_size();
62   params->content_size.SetSize(
63       settings.page_setup_device_units().content_area().width(),
64       settings.page_setup_device_units().content_area().height());
65   params->printable_area.SetRect(
66       settings.page_setup_device_units().printable_area().x(),
67       settings.page_setup_device_units().printable_area().y(),
68       settings.page_setup_device_units().printable_area().width(),
69       settings.page_setup_device_units().printable_area().height());
70   params->margin_top = settings.page_setup_device_units().content_area().y();
71   params->margin_left = settings.page_setup_device_units().content_area().x();
72   params->dpi = settings.dpi();
73   // Currently hardcoded at 1.25. See PrintSettings' constructor.
74   params->min_shrink = settings.min_shrink();
75   // Currently hardcoded at 2.0. See PrintSettings' constructor.
76   params->max_shrink = settings.max_shrink();
77   // Currently hardcoded at 72dpi. See PrintSettings' constructor.
78   params->desired_dpi = settings.desired_dpi();
79   // Always use an invalid cookie.
80   params->document_cookie = 0;
81   params->selection_only = settings.selection_only();
82   params->supports_alpha_blend = settings.supports_alpha_blend();
83   params->should_print_backgrounds = settings.should_print_backgrounds();
84   params->display_header_footer = settings.display_header_footer();
85   params->title = settings.title();
86   params->url = settings.url();
87 }
88
89 }  // namespace
90
91 PrintingMessageFilter::PrintingMessageFilter(int render_process_id,
92                                              Profile* profile)
93     : profile_io_data_(ProfileIOData::FromResourceContext(
94           profile->GetResourceContext())),
95       render_process_id_(render_process_id),
96       queue_(g_browser_process->print_job_manager()->queue()) {
97   DCHECK(queue_);
98 }
99
100 PrintingMessageFilter::~PrintingMessageFilter() {
101 }
102
103 void PrintingMessageFilter::OverrideThreadForMessage(
104     const IPC::Message& message, BrowserThread::ID* thread) {
105 #if defined(OS_CHROMEOS)
106   if (message.type() == PrintHostMsg_AllocateTempFileForPrinting::ID ||
107       message.type() == PrintHostMsg_TempFileForPrintingWritten::ID) {
108     *thread = BrowserThread::FILE;
109   }
110 #elif defined(OS_ANDROID)
111   if (message.type() == PrintHostMsg_AllocateTempFileForPrinting::ID ||
112       message.type() == PrintHostMsg_TempFileForPrintingWritten::ID) {
113     *thread = BrowserThread::UI;
114   }
115 #endif
116 }
117
118 bool PrintingMessageFilter::OnMessageReceived(const IPC::Message& message,
119                                               bool* message_was_ok) {
120   bool handled = true;
121   IPC_BEGIN_MESSAGE_MAP_EX(PrintingMessageFilter, message, *message_was_ok)
122 #if defined(OS_WIN)
123     IPC_MESSAGE_HANDLER(PrintHostMsg_DuplicateSection, OnDuplicateSection)
124 #endif
125 #if defined(OS_CHROMEOS) || defined(OS_ANDROID)
126     IPC_MESSAGE_HANDLER(PrintHostMsg_AllocateTempFileForPrinting,
127                         OnAllocateTempFileForPrinting)
128     IPC_MESSAGE_HANDLER(PrintHostMsg_TempFileForPrintingWritten,
129                         OnTempFileForPrintingWritten)
130 #endif
131     IPC_MESSAGE_HANDLER(PrintHostMsg_IsPrintingEnabled, OnIsPrintingEnabled)
132     IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_GetDefaultPrintSettings,
133                                     OnGetDefaultPrintSettings)
134     IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_ScriptedPrint, OnScriptedPrint)
135     IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_UpdatePrintSettings,
136                                     OnUpdatePrintSettings)
137 #if defined(ENABLE_FULL_PRINTING)
138     IPC_MESSAGE_HANDLER(PrintHostMsg_CheckForCancel, OnCheckForCancel)
139 #endif
140     IPC_MESSAGE_UNHANDLED(handled = false)
141   IPC_END_MESSAGE_MAP()
142   return handled;
143 }
144
145 #if defined(OS_WIN)
146 void PrintingMessageFilter::OnDuplicateSection(
147     base::SharedMemoryHandle renderer_handle,
148     base::SharedMemoryHandle* browser_handle) {
149   // Duplicate the handle in this process right now so the memory is kept alive
150   // (even if it is not mapped)
151   base::SharedMemory shared_buf(renderer_handle, true, PeerHandle());
152   shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), browser_handle);
153 }
154 #endif
155
156 #if defined(OS_CHROMEOS) || defined(OS_ANDROID)
157 void PrintingMessageFilter::OnAllocateTempFileForPrinting(
158     int render_view_id,
159     base::FileDescriptor* temp_file_fd,
160     int* sequence_number) {
161 #if defined(OS_CHROMEOS)
162   // TODO(thestig): Use |render_view_id| for Chrome OS.
163   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
164   temp_file_fd->fd = *sequence_number = -1;
165   temp_file_fd->auto_close = false;
166
167   SequenceToPathMap* map = &g_printing_file_descriptor_map.Get().map;
168   *sequence_number = g_printing_file_descriptor_map.Get().sequence++;
169
170   base::FilePath path;
171   if (base::CreateTemporaryFile(&path)) {
172     int fd = open(path.value().c_str(), O_WRONLY);
173     if (fd >= 0) {
174       SequenceToPathMap::iterator it = map->find(*sequence_number);
175       if (it != map->end()) {
176         NOTREACHED() << "Sequence number already in use. seq=" <<
177             *sequence_number;
178       } else {
179         (*map)[*sequence_number] = path;
180         temp_file_fd->fd = fd;
181         temp_file_fd->auto_close = true;
182       }
183     }
184   }
185 #elif defined(OS_ANDROID)
186   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
187   content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
188   if (!wc)
189     return;
190   printing::PrintViewManagerBasic* print_view_manager =
191       printing::PrintViewManagerBasic::FromWebContents(wc);
192   // The file descriptor is originally created in & passed from the Android
193   // side, and it will handle the closing.
194   const base::FileDescriptor& file_descriptor =
195       print_view_manager->file_descriptor();
196   temp_file_fd->fd = file_descriptor.fd;
197   temp_file_fd->auto_close = false;
198 #endif
199 }
200
201 void PrintingMessageFilter::OnTempFileForPrintingWritten(int render_view_id,
202                                                          int sequence_number) {
203 #if defined(OS_CHROMEOS)
204   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
205   SequenceToPathMap* map = &g_printing_file_descriptor_map.Get().map;
206   SequenceToPathMap::iterator it = map->find(sequence_number);
207   if (it == map->end()) {
208     NOTREACHED() << "Got a sequence that we didn't pass to the "
209                     "renderer: " << sequence_number;
210     return;
211   }
212   BrowserThread::PostTask(
213       BrowserThread::UI, FROM_HERE,
214       base::Bind(&PrintingMessageFilter::CreatePrintDialogForFile,
215                  this, render_view_id, it->second));
216
217   // Erase the entry in the map.
218   map->erase(it);
219 #elif defined(OS_ANDROID)
220   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
221   content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
222   if (!wc)
223     return;
224   printing::PrintViewManagerBasic* print_view_manager =
225       printing::PrintViewManagerBasic::FromWebContents(wc);
226   const base::FileDescriptor& file_descriptor =
227       print_view_manager->file_descriptor();
228   printing::PrintingContextAndroid::PdfWritingDone(file_descriptor.fd, true);
229   // Invalidate the file descriptor so it doesn't accidentally get reused.
230   print_view_manager->set_file_descriptor(base::FileDescriptor(-1, false));
231 #endif
232 }
233 #endif  // defined(OS_CHROMEOS) || defined(OS_ANDROID)
234
235 #if defined(OS_CHROMEOS)
236 void PrintingMessageFilter::CreatePrintDialogForFile(
237     int render_view_id,
238     const base::FilePath& path) {
239   content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
240   if (!wc)
241     return;
242   print_dialog_cloud::CreatePrintDialogForFile(
243       wc->GetBrowserContext(),
244       wc->GetView()->GetTopLevelNativeWindow(),
245       path,
246       wc->GetTitle(),
247       base::string16(),
248       std::string("application/pdf"),
249       false);
250 }
251 #endif  // defined(OS_CHROMEOS)
252
253 content::WebContents* PrintingMessageFilter::GetWebContentsForRenderView(
254     int render_view_id) {
255   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
256   content::RenderViewHost* view = content::RenderViewHost::FromID(
257       render_process_id_, render_view_id);
258   return view ? content::WebContents::FromRenderViewHost(view) : NULL;
259 }
260
261 struct PrintingMessageFilter::GetPrintSettingsForRenderViewParams {
262   printing::PrinterQuery::GetSettingsAskParam ask_user_for_settings;
263   int expected_page_count;
264   bool has_selection;
265   printing::MarginType margin_type;
266 };
267
268 void PrintingMessageFilter::GetPrintSettingsForRenderView(
269     int render_view_id,
270     GetPrintSettingsForRenderViewParams params,
271     const base::Closure& callback,
272     scoped_refptr<printing::PrinterQuery> printer_query) {
273   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
274   content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
275   if (wc) {
276     scoped_ptr<PrintingUIWebContentsObserver> wc_observer(
277         new PrintingUIWebContentsObserver(wc));
278     BrowserThread::PostTask(
279         BrowserThread::IO, FROM_HERE,
280         base::Bind(&printing::PrinterQuery::GetSettings, printer_query,
281                    params.ask_user_for_settings, base::Passed(&wc_observer),
282                    params.expected_page_count, params.has_selection,
283                    params.margin_type, callback));
284   } else {
285     BrowserThread::PostTask(
286         BrowserThread::IO, FROM_HERE,
287         base::Bind(&PrintingMessageFilter::OnGetPrintSettingsFailed, this,
288                    callback, printer_query));
289   }
290 }
291
292 void PrintingMessageFilter::OnGetPrintSettingsFailed(
293     const base::Closure& callback,
294     scoped_refptr<printing::PrinterQuery> printer_query) {
295   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
296   printer_query->GetSettingsDone(printing::PrintSettings(),
297                                  printing::PrintingContext::FAILED);
298   callback.Run();
299 }
300
301 void PrintingMessageFilter::OnIsPrintingEnabled(bool* is_enabled) {
302   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
303   *is_enabled = profile_io_data_->printing_enabled()->GetValue();
304 }
305
306 void PrintingMessageFilter::OnGetDefaultPrintSettings(IPC::Message* reply_msg) {
307   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
308   scoped_refptr<printing::PrinterQuery> printer_query;
309   if (!profile_io_data_->printing_enabled()->GetValue()) {
310     // Reply with NULL query.
311     OnGetDefaultPrintSettingsReply(printer_query, reply_msg);
312     return;
313   }
314   printer_query = queue_->PopPrinterQuery(0);
315   if (!printer_query)
316     printer_query = queue_->CreatePrinterQuery();
317
318   // Loads default settings. This is asynchronous, only the IPC message sender
319   // will hang until the settings are retrieved.
320   GetPrintSettingsForRenderViewParams params;
321   params.ask_user_for_settings = printing::PrinterQuery::DEFAULTS;
322   params.expected_page_count = 0;
323   params.has_selection = false;
324   params.margin_type = printing::DEFAULT_MARGINS;
325   BrowserThread::PostTask(
326       BrowserThread::UI, FROM_HERE,
327       base::Bind(&PrintingMessageFilter::GetPrintSettingsForRenderView, this,
328           reply_msg->routing_id(), params,
329           base::Bind(&PrintingMessageFilter::OnGetDefaultPrintSettingsReply,
330               this, printer_query, reply_msg),
331           printer_query));
332 }
333
334 void PrintingMessageFilter::OnGetDefaultPrintSettingsReply(
335     scoped_refptr<printing::PrinterQuery> printer_query,
336     IPC::Message* reply_msg) {
337   PrintMsg_Print_Params params;
338   if (!printer_query.get() ||
339       printer_query->last_status() != printing::PrintingContext::OK) {
340     params.Reset();
341   } else {
342     RenderParamsFromPrintSettings(printer_query->settings(), &params);
343     params.document_cookie = printer_query->cookie();
344   }
345   PrintHostMsg_GetDefaultPrintSettings::WriteReplyParams(reply_msg, params);
346   Send(reply_msg);
347   // If printing was enabled.
348   if (printer_query.get()) {
349     // If user hasn't cancelled.
350     if (printer_query->cookie() && printer_query->settings().dpi()) {
351       queue_->QueuePrinterQuery(printer_query.get());
352     } else {
353       printer_query->StopWorker();
354     }
355   }
356 }
357
358 void PrintingMessageFilter::OnScriptedPrint(
359     const PrintHostMsg_ScriptedPrint_Params& params,
360     IPC::Message* reply_msg) {
361   scoped_refptr<printing::PrinterQuery> printer_query =
362       queue_->PopPrinterQuery(params.cookie);
363   if (!printer_query)
364     printer_query = queue_->CreatePrinterQuery();
365   GetPrintSettingsForRenderViewParams settings_params;
366   settings_params.ask_user_for_settings = printing::PrinterQuery::ASK_USER;
367   settings_params.expected_page_count = params.expected_pages_count;
368   settings_params.has_selection = params.has_selection;
369   settings_params.margin_type = params.margin_type;
370
371   BrowserThread::PostTask(
372       BrowserThread::UI, FROM_HERE,
373       base::Bind(&PrintingMessageFilter::GetPrintSettingsForRenderView, this,
374                  reply_msg->routing_id(), settings_params,
375                  base::Bind(&PrintingMessageFilter::OnScriptedPrintReply, this,
376                             printer_query, reply_msg),
377                  printer_query));
378 }
379
380 void PrintingMessageFilter::OnScriptedPrintReply(
381     scoped_refptr<printing::PrinterQuery> printer_query,
382     IPC::Message* reply_msg) {
383   PrintMsg_PrintPages_Params params;
384 #if defined(OS_ANDROID)
385   // We need to save the routing ID here because Send method below deletes the
386   // |reply_msg| before we can get the routing ID for the Android code.
387   int routing_id = reply_msg->routing_id();
388 #endif
389   if (printer_query->last_status() != printing::PrintingContext::OK ||
390       !printer_query->settings().dpi()) {
391     params.Reset();
392   } else {
393     RenderParamsFromPrintSettings(printer_query->settings(), &params.params);
394     params.params.document_cookie = printer_query->cookie();
395     params.pages =
396         printing::PageRange::GetPages(printer_query->settings().ranges());
397   }
398   PrintHostMsg_ScriptedPrint::WriteReplyParams(reply_msg, params);
399   Send(reply_msg);
400   if (params.params.dpi && params.params.document_cookie) {
401 #if defined(OS_ANDROID)
402     int file_descriptor;
403     const base::string16& device_name = printer_query->settings().device_name();
404     if (base::StringToInt(device_name, &file_descriptor)) {
405       BrowserThread::PostTask(
406           BrowserThread::UI, FROM_HERE,
407           base::Bind(&PrintingMessageFilter::UpdateFileDescriptor, this,
408                      routing_id, file_descriptor));
409     }
410 #endif
411     queue_->QueuePrinterQuery(printer_query.get());
412   } else {
413     printer_query->StopWorker();
414   }
415 }
416
417 #if defined(OS_ANDROID)
418 void PrintingMessageFilter::UpdateFileDescriptor(int render_view_id, int fd) {
419   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
420   content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
421   if (!wc)
422     return;
423   printing::PrintViewManagerBasic* print_view_manager =
424       printing::PrintViewManagerBasic::FromWebContents(wc);
425   print_view_manager->set_file_descriptor(base::FileDescriptor(fd, false));
426 }
427 #endif
428
429 void PrintingMessageFilter::OnUpdatePrintSettings(
430     int document_cookie, const base::DictionaryValue& job_settings,
431     IPC::Message* reply_msg) {
432   scoped_refptr<printing::PrinterQuery> printer_query;
433   if (!profile_io_data_->printing_enabled()->GetValue()) {
434     // Reply with NULL query.
435     OnUpdatePrintSettingsReply(printer_query, reply_msg);
436     return;
437   }
438   printer_query = queue_->PopPrinterQuery(document_cookie);
439   if (!printer_query)
440     printer_query = queue_->CreatePrinterQuery();
441   printer_query->SetSettings(
442       job_settings,
443       base::Bind(&PrintingMessageFilter::OnUpdatePrintSettingsReply, this,
444                  printer_query, reply_msg));
445 }
446
447 void PrintingMessageFilter::OnUpdatePrintSettingsReply(
448     scoped_refptr<printing::PrinterQuery> printer_query,
449     IPC::Message* reply_msg) {
450   PrintMsg_PrintPages_Params params;
451   if (!printer_query.get() ||
452       printer_query->last_status() != printing::PrintingContext::OK) {
453     params.Reset();
454   } else {
455     RenderParamsFromPrintSettings(printer_query->settings(), &params.params);
456     params.params.document_cookie = printer_query->cookie();
457     params.pages =
458         printing::PageRange::GetPages(printer_query->settings().ranges());
459   }
460   PrintHostMsg_UpdatePrintSettings::WriteReplyParams(reply_msg, params);
461   Send(reply_msg);
462   // If user hasn't cancelled.
463   if (printer_query.get()) {
464     if (printer_query->cookie() && printer_query->settings().dpi()) {
465       queue_->QueuePrinterQuery(printer_query.get());
466     } else {
467       printer_query->StopWorker();
468     }
469   }
470 }
471
472 #if defined(ENABLE_FULL_PRINTING)
473 void PrintingMessageFilter::OnCheckForCancel(int32 preview_ui_id,
474                                              int preview_request_id,
475                                              bool* cancel) {
476   PrintPreviewUI::GetCurrentPrintPreviewStatus(preview_ui_id,
477                                                preview_request_id,
478                                                cancel);
479 }
480 #endif