Add printToPDF Implementation.

This commit is contained in:
Haojian Wu 2015-05-31 11:01:35 +08:00
parent b360f7d86a
commit 7ffa7042b1
10 changed files with 1112 additions and 2 deletions

View file

@ -0,0 +1,237 @@
// Copyright (c) 2012 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 "chrome/browser/printing/print_preview_message_handler.h"
#include <vector>
#include "atom/browser/ui/file_dialog.h"
#include "atom/browser/native_window.h"
#include "base/bind.h"
#include "base/json/json_reader.h"
#include "base/memory/ref_counted.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/shared_memory.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/printing/print_job_manager.h"
#include "chrome/browser/printing/printer_query.h"
#include "chrome/common/print_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "printing/page_size_margins.h"
#include "printing/print_job_constants.h"
#include "printing/pdf_metafile_skia.h"
using content::BrowserThread;
using content::WebContents;
DEFINE_WEB_CONTENTS_USER_DATA_KEY(printing::PrintPreviewMessageHandler);
namespace {
void StopWorker(int document_cookie) {
if (document_cookie <= 0)
return;
scoped_refptr<printing::PrintQueriesQueue> queue =
g_browser_process->print_job_manager()->queue();
scoped_refptr<printing::PrinterQuery> printer_query =
queue->PopPrinterQuery(document_cookie);
if (printer_query.get()) {
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&printing::PrinterQuery::StopWorker,
printer_query));
}
}
base::RefCountedBytes* GetDataFromHandle(base::SharedMemoryHandle handle,
uint32 data_size) {
scoped_ptr<base::SharedMemory> shared_buf(
new base::SharedMemory(handle, true));
if (!shared_buf->Map(data_size)) {
NOTREACHED();
return NULL;
}
unsigned char* data_begin = static_cast<unsigned char*>(shared_buf->memory());
std::vector<unsigned char> data(data_begin, data_begin + data_size);
return base::RefCountedBytes::TakeVector(&data);
}
} // namespace
namespace printing {
PrintPreviewMessageHandler::PrintPreviewMessageHandler(
WebContents* web_contents)
: content::WebContentsObserver(web_contents) {
DCHECK(web_contents);
}
PrintPreviewMessageHandler::~PrintPreviewMessageHandler() {
}
void PrintPreviewMessageHandler::OnDidGetPreviewPageCount(
const PrintHostMsg_DidGetPreviewPageCount_Params& params) {
if (params.page_count <= 0) {
NOTREACHED();
return;
}
LOG(ERROR) << "OnDidGetPreviewPageCount: " << params.page_count;
}
void PrintPreviewMessageHandler::OnDidPreviewPage(
const PrintHostMsg_DidPreviewPage_Params& params) {
int page_number = params.page_number;
if (page_number < FIRST_PAGE_INDEX || !params.data_size)
return;
LOG(ERROR) << "OnDidPreviewPage: " << params.data_size;
}
void PrintPreviewMessageHandler::OnMetafileReadyForPrinting(
const PrintHostMsg_DidPreviewDocument_Params& params) {
// Always try to stop the worker.
StopWorker(params.document_cookie);
if (params.expected_pages_count <= 0) {
NOTREACHED();
return;
}
// TODO(joth): This seems like a good match for using RefCountedStaticMemory
// to avoid the memory copy, but the SetPrintPreviewData call chain below
// needs updating to accept the RefCountedMemory* base class.
scoped_refptr<base::RefCountedBytes> data(
GetDataFromHandle(params.metafile_data_handle, params.data_size));
if (!data || !data->size())
return;
LOG(ERROR) << params.preview_request_id;
atom::NativeWindow* window = atom::NativeWindow::FromWebContents(
web_contents());
base::FilePath save_path;
file_dialog::ShowSaveDialog(window, "Save As",
base::FilePath(FILE_PATH_LITERAL("print.pdf")),
file_dialog::Filters(), &save_path);
printing::PdfMetafileSkia metafile;
metafile.InitFromData(static_cast<const void*>(data->front()), data->size());
base::File file(save_path,
base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
metafile.SaveTo(&file);
}
//void PrintPreviewMessageHandler::OnPrintPreviewFailed(int document_cookie) {
//StopWorker(document_cookie);
////PrintPreviewUI* print_preview_ui = GetPrintPreviewUI();
////if (!print_preview_ui)
////return;
////print_preview_ui->OnPrintPreviewFailed();
//}
//void PrintPreviewMessageHandler::OnDidGetDefaultPageLayout(
//const PageSizeMargins& page_layout_in_points,
//const gfx::Rect& printable_area_in_points,
//bool has_custom_page_size_style) {
////PrintPreviewUI* print_preview_ui = GetPrintPreviewUI();
////if (!print_preview_ui)
////return;
////print_preview_ui->OnDidGetDefaultPageLayout(page_layout_in_points,
////printable_area_in_points,
////has_custom_page_size_style);
//}
//void PrintPreviewMessageHandler::OnPrintPreviewCancelled(int document_cookie) {
//// Always need to stop the worker.
//StopWorker(document_cookie);
//}
//void PrintPreviewMessageHandler::OnInvalidPrinterSettings(int document_cookie) {
//StopWorker(document_cookie);
////PrintPreviewUI* print_preview_ui = GetPrintPreviewUI();
////if (!print_preview_ui)
////return;
////print_preview_ui->OnInvalidPrinterSettings();
//}
//void PrintPreviewMessageHandler::OnSetOptionsFromDocument(
//const PrintHostMsg_SetOptionsFromDocument_Params& params) {
////PrintPreviewUI* print_preview_ui = GetPrintPreviewUI();
////if (!print_preview_ui)
////return;
////print_preview_ui->OnSetOptionsFromDocument(params);
//}
bool PrintPreviewMessageHandler::OnMessageReceived(
const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PrintPreviewMessageHandler, message)
IPC_MESSAGE_HANDLER(PrintHostMsg_DidGetPreviewPageCount,
OnDidGetPreviewPageCount)
IPC_MESSAGE_HANDLER(PrintHostMsg_DidPreviewPage,
OnDidPreviewPage)
IPC_MESSAGE_HANDLER(PrintHostMsg_MetafileReadyForPrinting,
OnMetafileReadyForPrinting)
//IPC_MESSAGE_HANDLER(PrintHostMsg_PrintPreviewFailed,
//OnPrintPreviewFailed)
//IPC_MESSAGE_HANDLER(PrintHostMsg_DidGetDefaultPageLayout,
//OnDidGetDefaultPageLayout)
//IPC_MESSAGE_HANDLER(PrintHostMsg_PrintPreviewCancelled,
//OnPrintPreviewCancelled)
//IPC_MESSAGE_HANDLER(PrintHostMsg_PrintPreviewInvalidPrinterSettings,
//OnInvalidPrinterSettings)
//IPC_MESSAGE_HANDLER(PrintHostMsg_SetOptionsFromDocument,
//OnSetOptionsFromDocument)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void PrintPreviewMessageHandler::HandleGetPreview(const base::ListValue* args) {
static int request_id = 0;
request_id++;
// A simulated Chromium print preivew setting.
const std::string setting_json_str = "{ \
\"pageRage\":[], \
\"mediaSize\":{ \
\"height_microns\":297000, \
\"is_default\":true, \
\"name\":\"ISO_A4\", \
\"width_microns\":210000, \
\"custom_display_name\":\"A4\" \
}, \
\"landscape\":true, \
\"color\":2, \
\"headerFooterEnabled\":false, \
\"marginsType\":0, \
\"isFirstRequest\":false, \
\"requestID\":1, \
\"previewModifiable\":true, \
\"printToPDF\":true, \
\"printWithCloudPrint\":false, \
\"printWithPrivet\":false, \
\"printWithExtension\":false, \
\"deviceName\":\"Save as PDF\", \
\"generateDraftData\":true, \
\"fitToPageEnabled\":false, \
\"duplex\":0, \
\"copies\":1, \
\"collate\":true, \
\"shouldPrintBackgrounds\":true, \
\"shouldPrintSelectionOnly\":false \
}";
scoped_ptr<base::DictionaryValue> settings(
static_cast<base::DictionaryValue*>(
base::JSONReader::Read(setting_json_str)));
settings->SetInteger(printing::kPreviewRequestID, request_id);
LOG(ERROR) << "Print preview request start";
content::RenderViewHost* rvh = web_contents()->GetRenderViewHost();
rvh->Send(new PrintMsg_PrintPreview(rvh->GetRoutingID(), *settings));
}
} // namespace printing

View file

@ -0,0 +1,70 @@
// Copyright (c) 2012 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.
#ifndef CHROME_BROWSER_PRINTING_PRINT_PREVIEW_MESSAGE_HANDLER_H_
#define CHROME_BROWSER_PRINTING_PRINT_PREVIEW_MESSAGE_HANDLER_H_
#include "base/compiler_specific.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
struct PrintHostMsg_DidGetPreviewPageCount_Params;
struct PrintHostMsg_DidPreviewDocument_Params;
struct PrintHostMsg_DidPreviewPage_Params;
namespace content {
class WebContents;
}
namespace gfx {
class Rect;
}
namespace printing {
struct PageSizeMargins;
// Manages the print preview handling for a WebContents.
class PrintPreviewMessageHandler
: public content::WebContentsObserver,
public content::WebContentsUserData<PrintPreviewMessageHandler> {
public:
~PrintPreviewMessageHandler() override;
// content::WebContentsObserver implementation.
bool OnMessageReceived(const IPC::Message& message) override;
// Asks the initiator renderer to generate a preview. First element of |args|
// is a job settings JSON string.
void HandleGetPreview(const base::ListValue* args);
private:
explicit PrintPreviewMessageHandler(content::WebContents* web_contents);
friend class content::WebContentsUserData<PrintPreviewMessageHandler>;
// Message handlers.
//void OnRequestPrintPreview(
//const PrintHostMsg_RequestPrintPreview_Params& params);
//void OnDidGetDefaultPageLayout(
//const printing::PageSizeMargins& page_layout_in_points,
//const gfx::Rect& printable_area_in_points,
//bool has_custom_page_size_style);
void OnDidGetPreviewPageCount(
const PrintHostMsg_DidGetPreviewPageCount_Params& params);
void OnDidPreviewPage(const PrintHostMsg_DidPreviewPage_Params& params);
void OnMetafileReadyForPrinting(
const PrintHostMsg_DidPreviewDocument_Params& params);
//void OnPrintPreviewFailed(int document_cookie);
//void OnPrintPreviewCancelled(int document_cookie);
//void OnInvalidPrinterSettings(int document_cookie);
//void OnSetOptionsFromDocument(
//const PrintHostMsg_SetOptionsFromDocument_Params& params);
DISALLOW_COPY_AND_ASSIGN(PrintPreviewMessageHandler);
};
} // namespace printing
#endif // CHROME_BROWSER_PRINTING_PRINT_PREVIEW_MESSAGE_HANDLER_H_

View file

@ -128,6 +128,8 @@ bool PrintingMessageFilter::OnMessageReceived(const IPC::Message& message) {
IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_GetDefaultPrintSettings,
OnGetDefaultPrintSettings)
IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_ScriptedPrint, OnScriptedPrint)
IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_UpdatePrintSettings,
OnUpdatePrintSettings)
#if defined(ENABLE_FULL_PRINTING)
IPC_MESSAGE_HANDLER(PrintHostMsg_CheckForCancel, OnCheckForCancel)
#endif
@ -372,4 +374,57 @@ void PrintingMessageFilter::UpdateFileDescriptor(int render_view_id, int fd) {
}
#endif
void PrintingMessageFilter::OnUpdatePrintSettings(
int document_cookie, const base::DictionaryValue& job_settings,
IPC::Message* reply_msg) {
scoped_ptr<base::DictionaryValue> new_settings(job_settings.DeepCopy());
scoped_refptr<PrinterQuery> printer_query;
printer_query = queue_->PopPrinterQuery(document_cookie);
if (!printer_query.get()) {
int host_id = render_process_id_;
int routing_id = reply_msg->routing_id();
if (!new_settings->GetInteger(printing::kPreviewInitiatorHostId,
&host_id) ||
!new_settings->GetInteger(printing::kPreviewInitiatorRoutingId,
&routing_id)) {
host_id = content::ChildProcessHost::kInvalidUniqueID;
routing_id = content::ChildProcessHost::kInvalidUniqueID;
}
printer_query = queue_->CreatePrinterQuery(host_id, routing_id);
}
printer_query->SetSettings(
new_settings.Pass(),
base::Bind(&PrintingMessageFilter::OnUpdatePrintSettingsReply, this,
printer_query, reply_msg));
}
void PrintingMessageFilter::OnUpdatePrintSettingsReply(
scoped_refptr<PrinterQuery> printer_query,
IPC::Message* reply_msg) {
PrintMsg_PrintPages_Params params;
if (!printer_query.get() ||
printer_query->last_status() != PrintingContext::OK) {
params.Reset();
} else {
RenderParamsFromPrintSettings(printer_query->settings(), &params.params);
params.params.document_cookie = printer_query->cookie();
params.pages = PageRange::GetPages(printer_query->settings().ranges());
}
PrintHostMsg_UpdatePrintSettings::WriteReplyParams(
reply_msg,
params,
printer_query.get() &&
(printer_query->last_status() == printing::PrintingContext::CANCEL));
Send(reply_msg);
// If user hasn't cancelled.
if (printer_query.get()) {
if (printer_query->cookie() && printer_query->settings().dpi()) {
queue_->QueuePrinterQuery(printer_query.get());
} else {
printer_query->StopWorker();
}
}
}
} // namespace printing

View file

@ -96,6 +96,15 @@ class PrintingMessageFilter : public content::BrowserMessageFilter {
void OnScriptedPrintReply(scoped_refptr<PrinterQuery> printer_query,
IPC::Message* reply_msg);
// Modify the current print settings based on |job_settings|. The task is
// handled by the print worker thread and the UI thread. The reply occurs on
// the IO thread.
void OnUpdatePrintSettings(int document_cookie,
const base::DictionaryValue& job_settings,
IPC::Message* reply_msg);
void OnUpdatePrintSettingsReply(scoped_refptr<PrinterQuery> printer_query,
IPC::Message* reply_msg);
#if defined(ENABLE_FULL_PRINTING)
// Check to see if print preview has been cancelled.
void OnCheckForCancel(int32 preview_ui_id,