• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&params, 0, sizeof(params));
206   } else {
207     RenderParamsFromPrintSettings(printer_query->settings(), &params);
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(&params, 0, sizeof(params));
258   } else {
259     RenderParamsFromPrintSettings(printer_query->settings(), &params.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(&params, 0, sizeof(params));
294   } else {
295     RenderParamsFromPrintSettings(printer_query->settings(), &params.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