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 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 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 73 PrintingMessageFilter::~PrintingMessageFilter() { 74 } 75 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 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) 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) 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 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 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 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 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 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 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 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