Home | History | Annotate | Download | only in printing
      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/print_view_manager.h"
      6 
      7 #include <map>
      8 
      9 #include "base/bind.h"
     10 #include "base/lazy_instance.h"
     11 #include "base/metrics/histogram.h"
     12 #include "chrome/browser/browser_process.h"
     13 #include "chrome/browser/printing/print_job_manager.h"
     14 #include "chrome/browser/printing/print_preview_dialog_controller.h"
     15 #include "chrome/browser/printing/print_view_manager_observer.h"
     16 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
     17 #include "chrome/common/print_messages.h"
     18 #include "content/public/browser/browser_thread.h"
     19 #include "content/public/browser/web_contents.h"
     20 #include "printing/print_destination_interface.h"
     21 
     22 using content::BrowserThread;
     23 
     24 DEFINE_WEB_CONTENTS_USER_DATA_KEY(printing::PrintViewManager);
     25 
     26 namespace {
     27 
     28 // Keeps track of pending scripted print preview closures.
     29 // No locking, only access on the UI thread.
     30 typedef std::map<content::RenderProcessHost*, base::Closure>
     31     ScriptedPrintPreviewClosureMap;
     32 static base::LazyInstance<ScriptedPrintPreviewClosureMap>
     33     g_scripted_print_preview_closure_map = LAZY_INSTANCE_INITIALIZER;
     34 
     35 }  // namespace
     36 
     37 namespace printing {
     38 
     39 PrintViewManager::PrintViewManager(content::WebContents* web_contents)
     40     : PrintViewManagerBase(web_contents),
     41       observer_(NULL),
     42       print_preview_state_(NOT_PREVIEWING),
     43       scripted_print_preview_rph_(NULL) {
     44 }
     45 
     46 PrintViewManager::~PrintViewManager() {
     47   DCHECK_EQ(NOT_PREVIEWING, print_preview_state_);
     48 }
     49 
     50 bool PrintViewManager::PrintForSystemDialogNow() {
     51   return PrintNowInternal(new PrintMsg_PrintForSystemDialog(routing_id()));
     52 }
     53 
     54 bool PrintViewManager::AdvancedPrintNow() {
     55   PrintPreviewDialogController* dialog_controller =
     56       PrintPreviewDialogController::GetInstance();
     57   if (!dialog_controller)
     58     return false;
     59   content::WebContents* print_preview_dialog =
     60       dialog_controller->GetPrintPreviewForContents(web_contents());
     61   if (print_preview_dialog) {
     62     if (!print_preview_dialog->GetWebUI())
     63       return false;
     64     PrintPreviewUI* print_preview_ui = static_cast<PrintPreviewUI*>(
     65         print_preview_dialog->GetWebUI()->GetController());
     66     print_preview_ui->OnShowSystemDialog();
     67     return true;
     68   } else {
     69     return PrintNow();
     70   }
     71 }
     72 
     73 bool PrintViewManager::PrintToDestination() {
     74   // TODO(mad): Remove this once we can send user metrics from the metro driver.
     75   // crbug.com/142330
     76   UMA_HISTOGRAM_ENUMERATION("Metro.Print", 0, 2);
     77   // TODO(mad): Use a passed in destination interface instead.
     78   g_browser_process->print_job_manager()->queue()->SetDestination(
     79       printing::CreatePrintDestination());
     80   return PrintNowInternal(new PrintMsg_PrintPages(routing_id()));
     81 }
     82 
     83 bool PrintViewManager::PrintPreviewNow(bool selection_only) {
     84   // Users can send print commands all they want and it is beyond
     85   // PrintViewManager's control. Just ignore the extra commands.
     86   // See http://crbug.com/136842 for example.
     87   if (print_preview_state_ != NOT_PREVIEWING)
     88     return false;
     89 
     90   if (!PrintNowInternal(new PrintMsg_InitiatePrintPreview(routing_id(),
     91                                                           selection_only))) {
     92     return false;
     93   }
     94 
     95   print_preview_state_ = USER_INITIATED_PREVIEW;
     96   return true;
     97 }
     98 
     99 void PrintViewManager::PrintPreviewForWebNode() {
    100   if (print_preview_state_ != NOT_PREVIEWING)
    101     return;
    102   print_preview_state_ = USER_INITIATED_PREVIEW;
    103 }
    104 
    105 void PrintViewManager::PrintPreviewDone() {
    106   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    107   DCHECK_NE(NOT_PREVIEWING, print_preview_state_);
    108 
    109   if (print_preview_state_ == SCRIPTED_PREVIEW) {
    110     ScriptedPrintPreviewClosureMap& map =
    111         g_scripted_print_preview_closure_map.Get();
    112     ScriptedPrintPreviewClosureMap::iterator it =
    113         map.find(scripted_print_preview_rph_);
    114     CHECK(it != map.end());
    115     it->second.Run();
    116     map.erase(scripted_print_preview_rph_);
    117     scripted_print_preview_rph_ = NULL;
    118   }
    119   print_preview_state_ = NOT_PREVIEWING;
    120 }
    121 
    122 void PrintViewManager::set_observer(PrintViewManagerObserver* observer) {
    123   DCHECK(!observer || !observer_);
    124   observer_ = observer;
    125 }
    126 
    127 void PrintViewManager::RenderProcessGone(base::TerminationStatus status) {
    128   print_preview_state_ = NOT_PREVIEWING;
    129   PrintViewManagerBase::RenderProcessGone(status);
    130 }
    131 
    132 void PrintViewManager::OnDidShowPrintDialog() {
    133   if (observer_)
    134     observer_->OnPrintDialogShown();
    135 }
    136 
    137 void PrintViewManager::OnSetupScriptedPrintPreview(IPC::Message* reply_msg) {
    138   BrowserThread::CurrentlyOn(BrowserThread::UI);
    139   ScriptedPrintPreviewClosureMap& map =
    140       g_scripted_print_preview_closure_map.Get();
    141   content::RenderProcessHost* rph = web_contents()->GetRenderProcessHost();
    142 
    143   // This should always be 0 once we get modal window.print().
    144   if (map.count(rph) != 0) {
    145     // Renderer already handling window.print() in another View.
    146     Send(reply_msg);
    147     return;
    148   }
    149   if (print_preview_state_ != NOT_PREVIEWING) {
    150     // If a user initiated print dialog is already open, ignore the scripted
    151     // print message.
    152     DCHECK_EQ(USER_INITIATED_PREVIEW, print_preview_state_);
    153     Send(reply_msg);
    154     return;
    155   }
    156 
    157   PrintPreviewDialogController* dialog_controller =
    158       PrintPreviewDialogController::GetInstance();
    159   if (!dialog_controller) {
    160     Send(reply_msg);
    161     return;
    162   }
    163 
    164   print_preview_state_ = SCRIPTED_PREVIEW;
    165   base::Closure callback =
    166       base::Bind(&PrintViewManager::OnScriptedPrintPreviewReply,
    167                  base::Unretained(this),
    168                  reply_msg);
    169   map[rph] = callback;
    170   scripted_print_preview_rph_ = rph;
    171 }
    172 
    173 void PrintViewManager::OnShowScriptedPrintPreview(bool source_is_modifiable) {
    174   PrintPreviewDialogController* dialog_controller =
    175       PrintPreviewDialogController::GetInstance();
    176   if (!dialog_controller) {
    177     PrintPreviewDone();
    178     return;
    179   }
    180   dialog_controller->PrintPreview(web_contents());
    181   PrintHostMsg_RequestPrintPreview_Params params;
    182   params.is_modifiable = source_is_modifiable;
    183   PrintPreviewUI::SetInitialParams(
    184       dialog_controller->GetPrintPreviewForContents(web_contents()), params);
    185 }
    186 
    187 void PrintViewManager::OnScriptedPrintPreviewReply(IPC::Message* reply_msg) {
    188   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    189   Send(reply_msg);
    190 }
    191 
    192 bool PrintViewManager::OnMessageReceived(const IPC::Message& message) {
    193   bool handled = true;
    194   IPC_BEGIN_MESSAGE_MAP(PrintViewManager, message)
    195     IPC_MESSAGE_HANDLER(PrintHostMsg_DidShowPrintDialog, OnDidShowPrintDialog)
    196     IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_SetupScriptedPrintPreview,
    197                                     OnSetupScriptedPrintPreview)
    198     IPC_MESSAGE_HANDLER(PrintHostMsg_ShowScriptedPrintPreview,
    199                         OnShowScriptedPrintPreview)
    200     IPC_MESSAGE_UNHANDLED(handled = false)
    201   IPC_END_MESSAGE_MAP()
    202 
    203   return handled ? true : PrintViewManagerBase::OnMessageReceived(message);
    204 }
    205 
    206 }  // namespace printing
    207