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_preview_message_handler.h"
6
7#include <vector>
8
9#include "base/bind.h"
10#include "base/memory/ref_counted.h"
11#include "base/memory/ref_counted_memory.h"
12#include "base/memory/shared_memory.h"
13#include "chrome/browser/browser_process.h"
14#include "chrome/browser/printing/print_job_manager.h"
15#include "chrome/browser/printing/print_preview_dialog_controller.h"
16#include "chrome/browser/printing/print_view_manager.h"
17#include "chrome/browser/printing/printer_query.h"
18#include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
19#include "chrome/common/print_messages.h"
20#include "content/public/browser/browser_thread.h"
21#include "content/public/browser/render_view_host.h"
22#include "content/public/browser/web_contents.h"
23#include "content/public/browser/web_ui.h"
24#include "printing/page_size_margins.h"
25#include "printing/print_job_constants.h"
26
27using content::BrowserThread;
28using content::WebContents;
29
30DEFINE_WEB_CONTENTS_USER_DATA_KEY(printing::PrintPreviewMessageHandler);
31
32namespace {
33
34void StopWorker(int document_cookie) {
35  if (document_cookie <= 0)
36    return;
37  scoped_refptr<printing::PrintQueriesQueue> queue =
38      g_browser_process->print_job_manager()->queue();
39  scoped_refptr<printing::PrinterQuery> printer_query =
40      queue->PopPrinterQuery(document_cookie);
41  if (printer_query.get()) {
42    BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
43                            base::Bind(&printing::PrinterQuery::StopWorker,
44                                       printer_query));
45  }
46}
47
48base::RefCountedBytes* GetDataFromHandle(base::SharedMemoryHandle handle,
49                                         uint32 data_size) {
50  scoped_ptr<base::SharedMemory> shared_buf(
51      new base::SharedMemory(handle, true));
52  if (!shared_buf->Map(data_size)) {
53    NOTREACHED();
54    return NULL;
55  }
56
57  unsigned char* data_begin = static_cast<unsigned char*>(shared_buf->memory());
58  std::vector<unsigned char> data(data_begin, data_begin + data_size);
59  return base::RefCountedBytes::TakeVector(&data);
60}
61
62}  // namespace
63
64namespace printing {
65
66PrintPreviewMessageHandler::PrintPreviewMessageHandler(
67    WebContents* web_contents)
68    : content::WebContentsObserver(web_contents) {
69  DCHECK(web_contents);
70}
71
72PrintPreviewMessageHandler::~PrintPreviewMessageHandler() {
73}
74
75WebContents* PrintPreviewMessageHandler::GetPrintPreviewDialog() {
76  PrintPreviewDialogController* dialog_controller =
77      PrintPreviewDialogController::GetInstance();
78  if (!dialog_controller)
79    return NULL;
80  return dialog_controller->GetPrintPreviewForContents(web_contents());
81}
82
83PrintPreviewUI* PrintPreviewMessageHandler::GetPrintPreviewUI() {
84  WebContents* dialog = GetPrintPreviewDialog();
85  if (!dialog || !dialog->GetWebUI())
86    return NULL;
87  return static_cast<PrintPreviewUI*>(dialog->GetWebUI()->GetController());
88}
89
90void PrintPreviewMessageHandler::OnRequestPrintPreview(
91    const PrintHostMsg_RequestPrintPreview_Params& params) {
92  if (params.webnode_only) {
93    printing::PrintViewManager::FromWebContents(web_contents())->
94        PrintPreviewForWebNode();
95  }
96  PrintPreviewDialogController::PrintPreview(web_contents());
97  PrintPreviewUI::SetInitialParams(GetPrintPreviewDialog(), params);
98}
99
100void PrintPreviewMessageHandler::OnDidGetPreviewPageCount(
101    const PrintHostMsg_DidGetPreviewPageCount_Params& params) {
102  if (params.page_count <= 0) {
103    NOTREACHED();
104    return;
105  }
106
107  PrintPreviewUI* print_preview_ui = GetPrintPreviewUI();
108  if (!print_preview_ui)
109    return;
110
111  if (!params.is_modifiable || params.clear_preview_data)
112    print_preview_ui->ClearAllPreviewData();
113
114  print_preview_ui->OnDidGetPreviewPageCount(params);
115}
116
117void PrintPreviewMessageHandler::OnDidPreviewPage(
118    const PrintHostMsg_DidPreviewPage_Params& params) {
119  int page_number = params.page_number;
120  if (page_number < FIRST_PAGE_INDEX || !params.data_size)
121    return;
122
123  PrintPreviewUI* print_preview_ui = GetPrintPreviewUI();
124  if (!print_preview_ui)
125    return;
126
127  base::RefCountedBytes* data_bytes =
128      GetDataFromHandle(params.metafile_data_handle, params.data_size);
129  DCHECK(data_bytes);
130
131  print_preview_ui->SetPrintPreviewDataForIndex(page_number, data_bytes);
132  print_preview_ui->OnDidPreviewPage(page_number, params.preview_request_id);
133}
134
135void PrintPreviewMessageHandler::OnMetafileReadyForPrinting(
136    const PrintHostMsg_DidPreviewDocument_Params& params) {
137  // Always try to stop the worker.
138  StopWorker(params.document_cookie);
139
140  if (params.expected_pages_count <= 0) {
141    NOTREACHED();
142    return;
143  }
144
145  PrintPreviewUI* print_preview_ui = GetPrintPreviewUI();
146  if (!print_preview_ui)
147    return;
148
149  // TODO(joth): This seems like a good match for using RefCountedStaticMemory
150  // to avoid the memory copy, but the SetPrintPreviewData call chain below
151  // needs updating to accept the RefCountedMemory* base class.
152  base::RefCountedBytes* data_bytes =
153      GetDataFromHandle(params.metafile_data_handle, params.data_size);
154  if (!data_bytes || !data_bytes->size())
155    return;
156
157  print_preview_ui->SetPrintPreviewDataForIndex(COMPLETE_PREVIEW_DOCUMENT_INDEX,
158                                                data_bytes);
159  print_preview_ui->OnPreviewDataIsAvailable(
160      params.expected_pages_count, params.preview_request_id);
161}
162
163void PrintPreviewMessageHandler::OnPrintPreviewFailed(int document_cookie) {
164  StopWorker(document_cookie);
165
166  PrintPreviewUI* print_preview_ui = GetPrintPreviewUI();
167  if (!print_preview_ui)
168    return;
169  print_preview_ui->OnPrintPreviewFailed();
170}
171
172void PrintPreviewMessageHandler::OnDidGetDefaultPageLayout(
173    const PageSizeMargins& page_layout_in_points,
174    const gfx::Rect& printable_area_in_points,
175    bool has_custom_page_size_style) {
176  PrintPreviewUI* print_preview_ui = GetPrintPreviewUI();
177  if (!print_preview_ui)
178    return;
179  print_preview_ui->OnDidGetDefaultPageLayout(page_layout_in_points,
180                                              printable_area_in_points,
181                                              has_custom_page_size_style);
182}
183
184void PrintPreviewMessageHandler::OnPrintPreviewCancelled(int document_cookie) {
185  // Always need to stop the worker.
186  StopWorker(document_cookie);
187}
188
189void PrintPreviewMessageHandler::OnInvalidPrinterSettings(int document_cookie) {
190  StopWorker(document_cookie);
191  PrintPreviewUI* print_preview_ui = GetPrintPreviewUI();
192  if (!print_preview_ui)
193    return;
194  print_preview_ui->OnInvalidPrinterSettings();
195}
196
197void PrintPreviewMessageHandler::OnSetOptionsFromDocument(
198    const PrintHostMsg_SetOptionsFromDocument_Params& params) {
199  PrintPreviewUI* print_preview_ui = GetPrintPreviewUI();
200  if (!print_preview_ui)
201    return;
202  print_preview_ui->OnSetOptionsFromDocument(params);
203}
204
205bool PrintPreviewMessageHandler::OnMessageReceived(
206    const IPC::Message& message) {
207  bool handled = true;
208  IPC_BEGIN_MESSAGE_MAP(PrintPreviewMessageHandler, message)
209    IPC_MESSAGE_HANDLER(PrintHostMsg_RequestPrintPreview,
210                        OnRequestPrintPreview)
211    IPC_MESSAGE_HANDLER(PrintHostMsg_DidGetPreviewPageCount,
212                        OnDidGetPreviewPageCount)
213    IPC_MESSAGE_HANDLER(PrintHostMsg_DidPreviewPage,
214                        OnDidPreviewPage)
215    IPC_MESSAGE_HANDLER(PrintHostMsg_MetafileReadyForPrinting,
216                        OnMetafileReadyForPrinting)
217    IPC_MESSAGE_HANDLER(PrintHostMsg_PrintPreviewFailed,
218                        OnPrintPreviewFailed)
219    IPC_MESSAGE_HANDLER(PrintHostMsg_DidGetDefaultPageLayout,
220                        OnDidGetDefaultPageLayout)
221    IPC_MESSAGE_HANDLER(PrintHostMsg_PrintPreviewCancelled,
222                        OnPrintPreviewCancelled)
223    IPC_MESSAGE_HANDLER(PrintHostMsg_PrintPreviewInvalidPrinterSettings,
224                        OnInvalidPrinterSettings)
225    IPC_MESSAGE_HANDLER(PrintHostMsg_SetOptionsFromDocument,
226                        OnSetOptionsFromDocument)
227    IPC_MESSAGE_UNHANDLED(handled = false)
228  IPC_END_MESSAGE_MAP()
229  return handled;
230}
231
232}  // namespace printing
233