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 
     21 using content::BrowserThread;
     22 
     23 DEFINE_WEB_CONTENTS_USER_DATA_KEY(printing::PrintViewManager);
     24 
     25 namespace {
     26 
     27 // Keeps track of pending scripted print preview closures.
     28 // No locking, only access on the UI thread.
     29 typedef std::map<content::RenderProcessHost*, base::Closure>
     30     ScriptedPrintPreviewClosureMap;
     31 static base::LazyInstance<ScriptedPrintPreviewClosureMap>
     32     g_scripted_print_preview_closure_map = LAZY_INSTANCE_INITIALIZER;
     33 
     34 }  // namespace
     35 
     36 namespace printing {
     37 
     38 PrintViewManager::PrintViewManager(content::WebContents* web_contents)
     39     : PrintViewManagerBase(web_contents),
     40       observer_(NULL),
     41       print_preview_state_(NOT_PREVIEWING),
     42       scripted_print_preview_rph_(NULL) {
     43 }
     44 
     45 PrintViewManager::~PrintViewManager() {
     46   DCHECK_EQ(NOT_PREVIEWING, print_preview_state_);
     47 }
     48 
     49 #if !defined(DISABLE_BASIC_PRINTING)
     50 bool PrintViewManager::PrintForSystemDialogNow() {
     51   return PrintNowInternal(new PrintMsg_PrintForSystemDialog(routing_id()));
     52 }
     53 
     54 bool PrintViewManager::BasicPrint() {
     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 #endif  // !DISABLE_BASIC_PRINTING
     73 bool PrintViewManager::PrintPreviewNow(bool selection_only) {
     74   // Users can send print commands all they want and it is beyond
     75   // PrintViewManager's control. Just ignore the extra commands.
     76   // See http://crbug.com/136842 for example.
     77   if (print_preview_state_ != NOT_PREVIEWING)
     78     return false;
     79 
     80   if (!PrintNowInternal(new PrintMsg_InitiatePrintPreview(routing_id(),
     81                                                           selection_only))) {
     82     return false;
     83   }
     84 
     85   print_preview_state_ = USER_INITIATED_PREVIEW;
     86   return true;
     87 }
     88 
     89 void PrintViewManager::PrintPreviewForWebNode() {
     90   if (print_preview_state_ != NOT_PREVIEWING)
     91     return;
     92   print_preview_state_ = USER_INITIATED_PREVIEW;
     93 }
     94 
     95 void PrintViewManager::PrintPreviewDone() {
     96   DCHECK_CURRENTLY_ON(BrowserThread::UI);
     97   DCHECK_NE(NOT_PREVIEWING, print_preview_state_);
     98 
     99   if (print_preview_state_ == SCRIPTED_PREVIEW) {
    100     ScriptedPrintPreviewClosureMap& map =
    101         g_scripted_print_preview_closure_map.Get();
    102     ScriptedPrintPreviewClosureMap::iterator it =
    103         map.find(scripted_print_preview_rph_);
    104     CHECK(it != map.end());
    105     it->second.Run();
    106     map.erase(scripted_print_preview_rph_);
    107     scripted_print_preview_rph_ = NULL;
    108   }
    109   print_preview_state_ = NOT_PREVIEWING;
    110 }
    111 
    112 void PrintViewManager::set_observer(PrintViewManagerObserver* observer) {
    113   DCHECK(!observer || !observer_);
    114   observer_ = observer;
    115 }
    116 
    117 void PrintViewManager::RenderProcessGone(base::TerminationStatus status) {
    118   print_preview_state_ = NOT_PREVIEWING;
    119   PrintViewManagerBase::RenderProcessGone(status);
    120 }
    121 
    122 void PrintViewManager::OnDidShowPrintDialog() {
    123   if (observer_)
    124     observer_->OnPrintDialogShown();
    125 }
    126 
    127 void PrintViewManager::OnSetupScriptedPrintPreview(IPC::Message* reply_msg) {
    128   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    129   ScriptedPrintPreviewClosureMap& map =
    130       g_scripted_print_preview_closure_map.Get();
    131   content::RenderProcessHost* rph = web_contents()->GetRenderProcessHost();
    132 
    133   // This should always be 0 once we get modal window.print().
    134   if (map.count(rph) != 0) {
    135     // Renderer already handling window.print() in another View.
    136     Send(reply_msg);
    137     return;
    138   }
    139   if (print_preview_state_ != NOT_PREVIEWING) {
    140     // If a user initiated print dialog is already open, ignore the scripted
    141     // print message.
    142     DCHECK_EQ(USER_INITIATED_PREVIEW, print_preview_state_);
    143     Send(reply_msg);
    144     return;
    145   }
    146 
    147   PrintPreviewDialogController* dialog_controller =
    148       PrintPreviewDialogController::GetInstance();
    149   if (!dialog_controller) {
    150     Send(reply_msg);
    151     return;
    152   }
    153 
    154   print_preview_state_ = SCRIPTED_PREVIEW;
    155   base::Closure callback =
    156       base::Bind(&PrintViewManager::OnScriptedPrintPreviewReply,
    157                  base::Unretained(this),
    158                  reply_msg);
    159   map[rph] = callback;
    160   scripted_print_preview_rph_ = rph;
    161 }
    162 
    163 void PrintViewManager::OnShowScriptedPrintPreview(bool source_is_modifiable) {
    164   PrintPreviewDialogController* dialog_controller =
    165       PrintPreviewDialogController::GetInstance();
    166   if (!dialog_controller) {
    167     PrintPreviewDone();
    168     return;
    169   }
    170   dialog_controller->PrintPreview(web_contents());
    171   PrintHostMsg_RequestPrintPreview_Params params;
    172   params.is_modifiable = source_is_modifiable;
    173   PrintPreviewUI::SetInitialParams(
    174       dialog_controller->GetPrintPreviewForContents(web_contents()), params);
    175 }
    176 
    177 void PrintViewManager::OnScriptedPrintPreviewReply(IPC::Message* reply_msg) {
    178   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    179   Send(reply_msg);
    180 }
    181 
    182 bool PrintViewManager::OnMessageReceived(const IPC::Message& message) {
    183   bool handled = true;
    184   IPC_BEGIN_MESSAGE_MAP(PrintViewManager, message)
    185     IPC_MESSAGE_HANDLER(PrintHostMsg_DidShowPrintDialog, OnDidShowPrintDialog)
    186     IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_SetupScriptedPrintPreview,
    187                                     OnSetupScriptedPrintPreview)
    188     IPC_MESSAGE_HANDLER(PrintHostMsg_ShowScriptedPrintPreview,
    189                         OnShowScriptedPrintPreview)
    190     IPC_MESSAGE_UNHANDLED(handled = false)
    191   IPC_END_MESSAGE_MAP()
    192 
    193   return handled ? true : PrintViewManagerBase::OnMessageReceived(message);
    194 }
    195 
    196 }  // namespace printing
    197