Home | History | Annotate | Download | only in printing
      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(&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 
    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(&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 
    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(&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