Chromium Code Reviews| Index: headless/lib/browser/headless_print_manager.cc |
| diff --git a/headless/lib/browser/headless_print_manager.cc b/headless/lib/browser/headless_print_manager.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..72bf9fd1740760496d1a4d0082fb3e7d79d0067e |
| --- /dev/null |
| +++ b/headless/lib/browser/headless_print_manager.cc |
| @@ -0,0 +1,210 @@ |
| +// Copyright (c) 2017 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "headless/lib/browser/headless_print_manager.h" |
| + |
| +#include <utility> |
| +#include <vector> |
| + |
| +#include "base/base64.h" |
| +#include "components/printing/browser/print_manager_utils.h" |
| +#include "components/printing/common/print_messages.h" |
| +#include "printing/pdf_metafile_skia.h" |
| +#include "printing/print_settings.h" |
| +#include "printing/units.h" |
| + |
| +DEFINE_WEB_CONTENTS_USER_DATA_KEY(printing::HeadlessPrintManager); |
| + |
| +namespace printing { |
| + |
| +namespace { |
| + |
| +// TODO(jzfeng): let the print settings to be configurable. |
| +const double kTopMarginInInch = 0.25; |
| +const double kBottomMarginInInch = 0.56; |
| +const double kLeftMarginInInch = 0.25; |
| +const double kRightMarginInInch = 0.25; |
| + |
| +PrintSettings GetDefaultPDFPrinterSettings() { |
| + int dpi = printing::kDefaultPdfDpi; |
|
Lei Zhang
2017/03/29 01:38:03
No need for printing:: if you decide to keep this
jzfeng
2017/03/29 03:50:13
Done.
I feel it is ok to be under printing like Pr
Eric Seckler
2017/03/29 11:21:19
FWIW, either namespace is fine with me :)
|
| + gfx::Size physical_size_device_units; |
| + gfx::Rect printable_area_device_units; |
| + double page_width_in_pixel = printing::kLetterWidthInch * dpi; |
| + double page_height_in_pixel = printing::kLetterHeightInch * dpi; |
| + physical_size_device_units.SetSize(static_cast<int>(page_width_in_pixel), |
| + static_cast<int>(page_height_in_pixel)); |
| + printable_area_device_units.SetRect( |
| + static_cast<int>(kLeftMarginInInch * dpi), |
| + static_cast<int>(kTopMarginInInch * dpi), |
| + page_width_in_pixel - (kLeftMarginInInch + kRightMarginInInch) * dpi, |
| + page_height_in_pixel - (kTopMarginInInch + kBottomMarginInInch) * dpi); |
| + |
| + PrintSettings settings; |
| + settings.set_dpi(dpi); |
| + settings.SetPrinterPrintableArea(physical_size_device_units, |
| + printable_area_device_units, true); |
| + settings.set_should_print_backgrounds(true); |
| + return settings; |
| +} |
| + |
| +} // namespace |
| + |
| +HeadlessPrintManager::HeadlessPrintManager(content::WebContents* web_contents) |
| + : PrintManager(web_contents), |
| + printing_rfh_(nullptr), |
|
Lei Zhang
2017/03/29 01:38:03
Maybe implement a Reset() method and call it both
jzfeng
2017/03/29 03:50:13
Done.
|
| + is_active_(false), |
| +#if !defined(OS_MACOSX) |
| + expecting_first_page_(true) |
| +#endif |
| +{ |
| +} |
| + |
| +HeadlessPrintManager::~HeadlessPrintManager() {} |
| + |
| +// static |
| +std::string HeadlessPrintManager::PrintResultToErrMsg(PrintResult result) { |
| + switch (result) { |
| + case kPrintSuccess: |
| + return ""; // no error message |
| + case kPrintingFailed: |
| + return "PrintingFailed"; |
| + case kInvalidPrinterSettings: |
| + return "ShowInvalidPrinterSettingsError"; |
| + case kInvalidMemoryHandle: |
| + return "Invalid memory handle"; |
| + case kMetafileMapError: |
| + return "Map to SharedMemory error"; |
| + case kUnexpectedValidMemoryHandle: |
| + return "Unexpected valide memory handle"; |
| + case kMetafileInvalidHeader: |
| + return "Invalid metafile header"; |
| + case kMetafileGetDataError: |
| + return "Get data from metafile error"; |
| + case kDuplicatedPrintingError: |
| + return "The previous printing job hasn't finished"; |
| + default: |
| + return "Unknown PrintResult"; |
|
Lei Zhang
2017/03/29 01:38:03
Probably needs a NOTREACHED();
jzfeng
2017/03/29 03:50:13
Done.
|
| + } |
| +} |
| + |
| +// static |
| +std::unique_ptr<base::DictionaryValue> |
| +HeadlessPrintManager::PDFContentsToDictionaryValue(const std::string& data) { |
| + std::string base_64_data; |
| + base::Base64Encode(data, &base_64_data); |
| + std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue()); |
|
Lei Zhang
2017/03/29 01:38:03
auto result = base::MakeUnique<base::DictionaryVal
jzfeng
2017/03/29 03:50:13
Done.
|
| + result->SetString("data", base_64_data); |
| + return result; |
| +} |
| + |
| +bool HeadlessPrintManager::GetPDFContents(content::RenderFrameHost* rfh, |
| + GetPDFCallback callback) { |
| + if (is_active_) { |
| + callback.Run(kDuplicatedPrintingError, ""); |
| + return true; |
|
Lei Zhang
2017/03/29 01:38:03
Shouldn't this return false?
jzfeng
2017/03/29 03:50:13
I was thinking something else. Changed to just ret
|
| + } |
| + is_active_ = true; |
| + printing_rfh_ = rfh; |
| + callback_ = callback; |
| + return rfh->Send(new PrintMsg_PrintPages(rfh->GetRoutingID())); |
| +} |
| + |
| +bool HeadlessPrintManager::OnMessageReceived( |
| + const IPC::Message& message, |
| + content::RenderFrameHost* render_frame_host) { |
| + bool handled = true; |
| + IPC_BEGIN_MESSAGE_MAP(HeadlessPrintManager, message) |
| + IPC_MESSAGE_HANDLER(PrintHostMsg_ShowInvalidPrinterSettingsError, |
| + OnShowInvalidPrinterSettingsError) |
| + IPC_MESSAGE_HANDLER(PrintHostMsg_DidPrintPage, OnDidPrintPage) |
| + IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_GetDefaultPrintSettings, |
| + OnGetDefaultPrintSettings) |
| + IPC_MESSAGE_UNHANDLED(handled = false) |
| + IPC_END_MESSAGE_MAP() |
| + return handled || PrintManager::OnMessageReceived(message, render_frame_host); |
| +} |
| + |
| +void HeadlessPrintManager::OnGetDefaultPrintSettings(IPC::Message* reply_msg) { |
| + PrintMsg_Print_Params print_params; |
| + RenderParamsFromPrintSettings(GetDefaultPDFPrinterSettings(), &print_params); |
| + print_params.document_cookie = PrintSettings::NewCookie(); |
| + PrintHostMsg_GetDefaultPrintSettings::WriteReplyParams(reply_msg, |
| + print_params); |
| + printing_rfh_->Send(reply_msg); |
| +} |
| + |
| +void HeadlessPrintManager::OnShowInvalidPrinterSettingsError() { |
| + ReleaseJob(kInvalidPrinterSettings); |
| +} |
| + |
| +void HeadlessPrintManager::OnPrintingFailed(int cookie) { |
| + ReleaseJob(kPrintingFailed); |
| +} |
| + |
| +void HeadlessPrintManager::OnDidPrintPage( |
| + const PrintHostMsg_DidPrintPage_Params& params) { |
| +#if defined(OS_MACOSX) |
| + const bool metafile_must_be_valid = true; |
| +#else |
| + const bool metafile_must_be_valid = expecting_first_page_; |
| + expecting_first_page_ = false; |
| +#endif |
| + |
| + // Only used when |metafile_must_be_valid| is true. |
| + std::unique_ptr<base::SharedMemory> shared_buf; |
| + if (metafile_must_be_valid) { |
| + if (!base::SharedMemory::IsHandleValid(params.metafile_data_handle)) { |
| + ReleaseJob(kInvalidMemoryHandle); |
| + return; |
| + } |
| + shared_buf = |
| + base::MakeUnique<base::SharedMemory>(params.metafile_data_handle, true); |
| + if (!shared_buf->Map(params.data_size)) { |
| + ReleaseJob(kMetafileMapError); |
| + return; |
| + } |
| + } else { |
| + if (base::SharedMemory::IsHandleValid(params.metafile_data_handle)) { |
| + base::SharedMemory::CloseHandle(params.metafile_data_handle); |
| + ReleaseJob(kUnexpectedValidMemoryHandle); |
| + return; |
| + } |
| + } |
| + |
| + std::unique_ptr<PdfMetafileSkia> metafile( |
| + new PdfMetafileSkia(PDF_SKIA_DOCUMENT_TYPE)); |
|
Lei Zhang
2017/03/29 01:38:03
More base::MakeUnique. Basically try to avoid usin
jzfeng
2017/03/29 03:50:13
Cool. Also change some other places that use "new"
|
| + if (metafile_must_be_valid) { |
| + if (!metafile->InitFromData(shared_buf->memory(), params.data_size)) { |
| + ReleaseJob(kMetafileInvalidHeader); |
| + return; |
| + } |
| + std::vector<char> buffer; |
| + if (!metafile->GetDataAsVector(&buffer)) { |
| + ReleaseJob(kMetafileGetDataError); |
| + return; |
| + } |
| + data_ = std::string(buffer.data(), buffer.size()); |
| + } |
| + |
| + if (--number_pages_ == 0) |
| + ReleaseJob(kPrintSuccess); |
| +} |
| + |
| +void HeadlessPrintManager::ReleaseJob(PrintResult result) { |
| + if (result == kPrintSuccess) |
| + callback_.Run(result, std::move(data_)); |
| + else |
| + callback_.Run(result, ""); |
| + data_.clear(); |
| + number_pages_ = 0; |
| + printing_rfh_->Send(new PrintMsg_PrintingDone(printing_rfh_->GetRoutingID(), |
| + result == kPrintSuccess)); |
| + printing_rfh_ = nullptr; |
| + is_active_ = false; |
| +#if !defined(OS_MACOSX) |
| + expecting_first_page_ = true; |
| +#endif |
| +} |
| + |
| +} // namespace printing |