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/renderer/mock_printer.h"
6
7#include "base/basictypes.h"
8#include "base/file_util.h"
9#include "base/memory/shared_memory.h"
10#include "base/strings/string16.h"
11#include "base/strings/utf_string_conversions.h"
12#include "chrome/common/print_messages.h"
13#include "ipc/ipc_message_utils.h"
14#include "printing/metafile_impl.h"
15#include "printing/units.h"
16#include "testing/gtest/include/gtest/gtest.h"
17
18#if defined(OS_MACOSX)
19#include "printing/pdf_metafile_cg_mac.h"
20#endif
21
22namespace {
23
24void UpdateMargins(int margins_type, int dpi, PrintMsg_Print_Params* params) {
25  if (margins_type == printing::NO_MARGINS) {
26    params->content_size.SetSize(static_cast<int>((8.5 * dpi)),
27                                 static_cast<int>((11.0 * dpi)));
28    params->margin_left = 0;
29    params->margin_top = 0;
30  } else if (margins_type == printing::PRINTABLE_AREA_MARGINS) {
31    params->content_size.SetSize(static_cast<int>((8.0 * dpi)),
32                                 static_cast<int>((10.5 * dpi)));
33    params->margin_left = static_cast<int>(0.25 * dpi);
34    params->margin_top = static_cast<int>(0.25 * dpi);
35  } else if (margins_type == printing::CUSTOM_MARGINS) {
36    params->content_size.SetSize(static_cast<int>((7.9 * dpi)),
37                                 static_cast<int>((10.4 * dpi)));
38    params->margin_left = static_cast<int>(0.30 * dpi);
39    params->margin_top = static_cast<int>(0.30 * dpi);
40  }
41}
42
43} // end
44
45MockPrinterPage::MockPrinterPage(const void* source_data,
46                                 uint32 source_size,
47                                 const printing::Image& image)
48    : source_size_(source_size),
49      image_(image) {
50  // Create copies of the source data
51  source_data_.reset(new uint8[source_size]);
52  if (source_data_.get())
53    memcpy(source_data_.get(), source_data, source_size);
54}
55
56MockPrinterPage::~MockPrinterPage() {}
57
58MockPrinter::MockPrinter()
59  : dpi_(printing::kPointsPerInch),
60    max_shrink_(2.0),
61    min_shrink_(1.25),
62    desired_dpi_(printing::kPointsPerInch),
63    selection_only_(false),
64    should_print_backgrounds_(false),
65    document_cookie_(-1),
66    current_document_cookie_(0),
67    printer_status_(PRINTER_READY),
68    number_pages_(0),
69    page_number_(0),
70    is_first_request_(true),
71    print_to_pdf_(false),
72    preview_request_id_(0),
73    print_scaling_option_(WebKit::WebPrintScalingOptionSourceSize),
74    display_header_footer_(false),
75    date_(ASCIIToUTF16("date")),
76    title_(ASCIIToUTF16("title")),
77    url_(ASCIIToUTF16("url")),
78    use_invalid_settings_(false) {
79  page_size_.SetSize(static_cast<int>(8.5 * dpi_),
80                     static_cast<int>(11.0 * dpi_));
81  content_size_.SetSize(static_cast<int>((7.5 * dpi_)),
82                          static_cast<int>((10.0 * dpi_)));
83  margin_left_ = margin_top_ = static_cast<int>(0.5 * dpi_);
84  printable_area_.SetRect(static_cast<int>(0.25 * dpi_),
85                          static_cast<int>(0.25 *dpi_),
86                          static_cast<int>(8 * dpi_),
87                          static_cast<int>(10.5 * dpi_));
88}
89
90MockPrinter::~MockPrinter() {
91}
92
93void MockPrinter::ResetPrinter() {
94  printer_status_ = PRINTER_READY;
95  document_cookie_ = -1;
96}
97
98void MockPrinter::GetDefaultPrintSettings(PrintMsg_Print_Params* params) {
99  // Verify this printer is not processing a job.
100  // Sorry, this mock printer is very fragile.
101  EXPECT_EQ(-1, document_cookie_);
102
103  // Assign a unit document cookie and set the print settings.
104  document_cookie_ = CreateDocumentCookie();
105  params->Reset();
106  SetPrintParams(params);
107}
108
109void MockPrinter::SetDefaultPrintSettings(const PrintMsg_Print_Params& params) {
110  dpi_ = params.dpi;
111  max_shrink_ = params.max_shrink;
112  min_shrink_ = params.min_shrink;
113  desired_dpi_ = params.desired_dpi;
114  selection_only_ = params.selection_only;
115  should_print_backgrounds_ = params.should_print_backgrounds;
116  page_size_ = params.page_size;
117  content_size_ = params.content_size;
118  printable_area_ = params.printable_area;
119  margin_left_ = params.margin_left;
120  margin_top_ = params.margin_top;
121  display_header_footer_ = params.display_header_footer;
122  date_ = params.date;
123  title_ = params.title;
124  url_ = params.url;
125}
126
127void MockPrinter::UseInvalidSettings() {
128  use_invalid_settings_ = true;
129  PrintMsg_Print_Params empty_param;
130  SetDefaultPrintSettings(empty_param);
131}
132
133void MockPrinter::UseInvalidPageSize() {
134  page_size_.SetSize(0, 0);
135}
136
137void MockPrinter::UseInvalidContentSize() {
138  content_size_.SetSize(0, 0);
139}
140
141void MockPrinter::ScriptedPrint(int cookie,
142                                int expected_pages_count,
143                                bool has_selection,
144                                PrintMsg_PrintPages_Params* settings) {
145  // Verify the input parameters.
146  EXPECT_EQ(document_cookie_, cookie);
147
148  settings->Reset();
149
150  settings->params.dpi = dpi_;
151  settings->params.max_shrink = max_shrink_;
152  settings->params.min_shrink = min_shrink_;
153  settings->params.desired_dpi = desired_dpi_;
154  settings->params.selection_only = selection_only_;
155  settings->params.should_print_backgrounds = should_print_backgrounds_;
156  settings->params.document_cookie = document_cookie_;
157  settings->params.page_size = page_size_;
158  settings->params.content_size = content_size_;
159  settings->params.printable_area = printable_area_;
160  settings->params.is_first_request = is_first_request_;
161  settings->params.print_scaling_option = print_scaling_option_;
162  settings->params.print_to_pdf = print_to_pdf_;
163  settings->params.preview_request_id = preview_request_id_;
164  settings->params.display_header_footer = display_header_footer_;
165  settings->params.date = date_;
166  settings->params.title = title_;
167  settings->params.url = url_;
168  printer_status_ = PRINTER_PRINTING;
169}
170
171void MockPrinter::UpdateSettings(int cookie,
172                                 PrintMsg_PrintPages_Params* params,
173                                 const std::vector<int>& pages,
174                                 int margins_type) {
175  if (document_cookie_ == -1) {
176    document_cookie_ = CreateDocumentCookie();
177  }
178  params->Reset();
179  params->pages = pages;
180  SetPrintParams(&(params->params));
181  UpdateMargins(margins_type, dpi_, &(params->params));
182  printer_status_ = PRINTER_PRINTING;
183}
184
185void MockPrinter::SetPrintedPagesCount(int cookie, int number_pages) {
186  // Verify the input parameter and update the printer status so that the
187  // RenderViewTest class can verify the this function finishes without errors.
188  EXPECT_EQ(document_cookie_, cookie);
189  EXPECT_EQ(PRINTER_PRINTING, printer_status_);
190  EXPECT_EQ(0, number_pages_);
191  EXPECT_EQ(0, page_number_);
192
193  // Initialize the job status.
194  number_pages_ = number_pages;
195  page_number_ = 0;
196  pages_.clear();
197}
198
199void MockPrinter::PrintPage(const PrintHostMsg_DidPrintPage_Params& params) {
200  // Verify the input parameter and update the printer status so that the
201  // RenderViewTest class can verify the this function finishes without errors.
202  EXPECT_EQ(PRINTER_PRINTING, printer_status_);
203  EXPECT_EQ(document_cookie_, params.document_cookie);
204  EXPECT_EQ(page_number_, params.page_number);
205  EXPECT_LE(params.page_number, number_pages_);
206
207#if defined(OS_WIN) || defined(OS_MACOSX)
208  // Load the data sent from a RenderView object and create a PageData object.
209  // We duplicate the given file handle when creating a base::SharedMemory
210  // instance so that its destructor closes the copy.
211  EXPECT_GT(params.data_size, 0U);
212#if defined(OS_WIN)
213  base::SharedMemory metafile_data(params.metafile_data_handle, true,
214                                   GetCurrentProcess());
215#elif defined(OS_MACOSX)
216  base::SharedMemory metafile_data(params.metafile_data_handle, true);
217#endif
218  metafile_data.Map(params.data_size);
219#if defined(OS_MACOSX)
220  printing::PdfMetafileCg metafile;
221#else
222  printing::NativeMetafile metafile;
223#endif
224  metafile.InitFromData(metafile_data.memory(), params.data_size);
225  printing::Image image(metafile);
226  MockPrinterPage* page_data = new MockPrinterPage(metafile_data.memory(),
227                                                   params.data_size,
228                                                   image);
229  if (!page_data) {
230    printer_status_ = PRINTER_ERROR;
231    return;
232  }
233
234  scoped_refptr<MockPrinterPage> page(page_data);
235  pages_.push_back(page);
236#endif
237
238  // We finish printing a printing job.
239  // Reset the job status and the printer status.
240  ++page_number_;
241  if (number_pages_ == page_number_)
242    ResetPrinter();
243}
244
245int MockPrinter::GetPrintedPages() const {
246  if (printer_status_ != PRINTER_READY)
247    return -1;
248  return page_number_;
249}
250
251const MockPrinterPage* MockPrinter::GetPrintedPage(unsigned int pageno) const {
252  if (pages_.size() > pageno)
253    return pages_[pageno].get();
254  else
255    return NULL;
256}
257
258int MockPrinter::GetWidth(unsigned int page) const {
259  if (printer_status_ != PRINTER_READY || page >= pages_.size())
260    return -1;
261  return pages_[page]->width();
262}
263
264int MockPrinter::GetHeight(unsigned int page) const {
265  if (printer_status_ != PRINTER_READY || page >= pages_.size())
266    return -1;
267  return pages_[page]->height();
268}
269
270bool MockPrinter::GetBitmapChecksum(
271    unsigned int page, std::string* checksum) const {
272  if (printer_status_ != PRINTER_READY || page >= pages_.size())
273    return false;
274  *checksum = pages_[page]->image().checksum();
275  return true;
276}
277
278bool MockPrinter::SaveSource(
279    unsigned int page, const base::FilePath& filepath) const {
280  if (printer_status_ != PRINTER_READY || page >= pages_.size())
281    return false;
282  const uint8* source_data = pages_[page]->source_data();
283  uint32 source_size = pages_[page]->source_size();
284  file_util::WriteFile(filepath, reinterpret_cast<const char*>(source_data),
285                       source_size);
286  return true;
287}
288
289bool MockPrinter::SaveBitmap(
290    unsigned int page, const base::FilePath& filepath) const {
291  if (printer_status_ != PRINTER_READY || page >= pages_.size())
292    return false;
293
294  pages_[page]->image().SaveToPng(filepath);
295  return true;
296}
297
298int MockPrinter::CreateDocumentCookie() {
299  return use_invalid_settings_ ? 0 : ++current_document_cookie_;
300}
301
302void MockPrinter::SetPrintParams(PrintMsg_Print_Params* params) {
303  params->dpi = dpi_;
304  params->max_shrink = max_shrink_;
305  params->min_shrink = min_shrink_;
306  params->desired_dpi = desired_dpi_;
307  params->selection_only = selection_only_;
308  params->should_print_backgrounds = should_print_backgrounds_;
309  params->document_cookie = document_cookie_;
310  params->page_size = page_size_;
311  params->content_size = content_size_;
312  params->printable_area = printable_area_;
313  params->margin_left = margin_left_;
314  params->margin_top = margin_top_;
315  params->is_first_request = is_first_request_;
316  params->print_scaling_option = print_scaling_option_;
317  params->print_to_pdf = print_to_pdf_;
318  params->preview_request_id = preview_request_id_;
319  params->display_header_footer = display_header_footer_;
320  params->date = date_;
321  params->title = title_;
322  params->url = url_;
323}
324