From b360f7d86a3b00be4235057e971c25d9948edaf7 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Sun, 31 May 2015 10:24:45 +0800 Subject: [PATCH 01/28] Add printToPDF API skeleton. --- atom/browser/api/atom_api_window.cc | 5 +++++ atom/browser/api/atom_api_window.h | 1 + atom/browser/native_window.cc | 3 +++ atom/browser/native_window.h | 3 +++ 4 files changed, 12 insertions(+) diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 7461bc736855..00a0bb464089 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -430,6 +430,10 @@ void Window::Print(mate::Arguments* args) { window_->Print(settings.silent, settings.print_background); } +void Window::PrintToPDF() { + window_->PrintToPDF(); +} + void Window::SetProgressBar(double progress) { window_->SetProgressBar(progress); } @@ -542,6 +546,7 @@ void Window::BuildPrototype(v8::Isolate* isolate, .SetMethod("isWebViewFocused", &Window::IsWebViewFocused) .SetMethod("capturePage", &Window::CapturePage) .SetMethod("print", &Window::Print) + .SetMethod("printToPDF", &Window::PrintToPDF) .SetMethod("setProgressBar", &Window::SetProgressBar) .SetMethod("setOverlayIcon", &Window::SetOverlayIcon) .SetMethod("_setMenu", &Window::SetMenu) diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index 43a32e86f45a..606fda9f7dc3 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -132,6 +132,7 @@ class Window : public mate::EventEmitter, bool IsDocumentEdited(); void CapturePage(mate::Arguments* args); void Print(mate::Arguments* args); + void PrintToPDF(); void SetProgressBar(double progress); void SetOverlayIcon(const gfx::Image& overlay, const std::string& description); diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 8eb05cb9b0f2..f0198996668d 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -262,6 +262,9 @@ void NativeWindow::Print(bool silent, bool print_background) { PrintNow(silent, print_background); } +void NativeWindow::PrintToPDF() { +} + void NativeWindow::ShowDefinitionForSelection() { NOTIMPLEMENTED(); } diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index 2038775f8d9a..5c99a2c117b5 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -157,6 +157,9 @@ class NativeWindow : public CommonWebContentsDelegate, // Print current page. virtual void Print(bool silent, bool print_background); + // Print current page as PDF. + virtual void PrintToPDF(); + // Show popup dictionary. virtual void ShowDefinitionForSelection(); From 7ffa7042b1c6becad7e20e8fb8f9d182b575475c Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Sun, 31 May 2015 11:01:35 +0800 Subject: [PATCH 02/28] Add printToPDF Implementation. --- atom/browser/native_window.cc | 5 + .../printing/print_preview_message_handler.cc | 237 +++++++++ .../printing/print_preview_message_handler.h | 70 +++ .../printing/printing_message_filter.cc | 55 ++ .../printing/printing_message_filter.h | 9 + chromium_src/chrome/common/print_messages.h | 85 +++ .../printing/print_web_view_helper.cc | 490 ++++++++++++++++++ .../renderer/printing/print_web_view_helper.h | 159 ++++++ .../printing/print_web_view_helper_pdf_win.cc | 2 - filenames.gypi | 2 + 10 files changed, 1112 insertions(+), 2 deletions(-) create mode 100644 chromium_src/chrome/browser/printing/print_preview_message_handler.cc create mode 100644 chromium_src/chrome/browser/printing/print_preview_message_handler.h diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index f0198996668d..9b922dc9b5b0 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -28,6 +28,8 @@ #include "brightray/browser/inspectable_web_contents.h" #include "brightray/browser/inspectable_web_contents_view.h" #include "chrome/browser/printing/print_view_manager_basic.h" +#include "chrome/browser/printing/print_preview_message_handler.h" +#include "chrome/browser/ui/browser_dialogs.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/notification_details.h" @@ -97,6 +99,7 @@ NativeWindow::NativeWindow(content::WebContents* web_contents, zoom_factor_(1.0), weak_factory_(this) { printing::PrintViewManagerBasic::CreateForWebContents(web_contents); + printing::PrintPreviewMessageHandler::CreateForWebContents(web_contents); InitWithWebContents(web_contents, this); @@ -263,6 +266,8 @@ void NativeWindow::Print(bool silent, bool print_background) { } void NativeWindow::PrintToPDF() { + printing::PrintPreviewMessageHandler::FromWebContents(GetWebContents())-> + HandleGetPreview(NULL); } void NativeWindow::ShowDefinitionForSelection() { diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc new file mode 100644 index 000000000000..6cc47e90876f --- /dev/null +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc @@ -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 + +#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 queue = + g_browser_process->print_job_manager()->queue(); + scoped_refptr 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 shared_buf( + new base::SharedMemory(handle, true)); + if (!shared_buf->Map(data_size)) { + NOTREACHED(); + return NULL; + } + + unsigned char* data_begin = static_cast(shared_buf->memory()); + std::vector 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 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(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 settings( + static_cast( + 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 diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.h b/chromium_src/chrome/browser/printing/print_preview_message_handler.h new file mode 100644 index 000000000000..8f9f1b4ed230 --- /dev/null +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.h @@ -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 { + 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; + + + // 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_ diff --git a/chromium_src/chrome/browser/printing/printing_message_filter.cc b/chromium_src/chrome/browser/printing/printing_message_filter.cc index 15ca50fba53f..6fd536ef68c3 100644 --- a/chromium_src/chrome/browser/printing/printing_message_filter.cc +++ b/chromium_src/chrome/browser/printing/printing_message_filter.cc @@ -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 new_settings(job_settings.DeepCopy()); + + scoped_refptr 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 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(), ¶ms.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 diff --git a/chromium_src/chrome/browser/printing/printing_message_filter.h b/chromium_src/chrome/browser/printing/printing_message_filter.h index 410b6245786d..624b28fd35dd 100644 --- a/chromium_src/chrome/browser/printing/printing_message_filter.h +++ b/chromium_src/chrome/browser/printing/printing_message_filter.h @@ -96,6 +96,15 @@ class PrintingMessageFilter : public content::BrowserMessageFilter { void OnScriptedPrintReply(scoped_refptr 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 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, diff --git a/chromium_src/chrome/common/print_messages.h b/chromium_src/chrome/common/print_messages.h index 4a54546b69d7..2e6d23771676 100644 --- a/chromium_src/chrome/common/print_messages.h +++ b/chromium_src/chrome/common/print_messages.h @@ -46,7 +46,9 @@ struct PrintMsg_Print_Params { int document_cookie; bool selection_only; bool supports_alpha_blend; + int preview_request_id; blink::WebPrintScalingOption print_scaling_option; + bool print_to_pdf; base::string16 title; base::string16 url; bool should_print_backgrounds; @@ -185,6 +187,61 @@ IPC_STRUCT_BEGIN(PrintHostMsg_ScriptedPrint_Params) IPC_STRUCT_MEMBER(printing::MarginType, margin_type) IPC_STRUCT_END() +// Parameters to describe a rendered preview page. +IPC_STRUCT_BEGIN(PrintHostMsg_DidPreviewPage_Params) + // A shared memory handle to metafile data for a draft document of the page. + IPC_STRUCT_MEMBER(base::SharedMemoryHandle, metafile_data_handle) + + // Size of metafile data. + IPC_STRUCT_MEMBER(uint32, data_size) + + // |page_number| is zero-based and can be |printing::INVALID_PAGE_INDEX| if it + // is just a check. + IPC_STRUCT_MEMBER(int, page_number) + + // The id of the preview request. + IPC_STRUCT_MEMBER(int, preview_request_id) +IPC_STRUCT_END() + +// Parameters sent along with the page count. +IPC_STRUCT_BEGIN(PrintHostMsg_DidGetPreviewPageCount_Params) + // Cookie for the document to ensure correctness. + IPC_STRUCT_MEMBER(int, document_cookie) + + // Total page count. + IPC_STRUCT_MEMBER(int, page_count) + + // Indicates whether the previewed document is modifiable. + IPC_STRUCT_MEMBER(bool, is_modifiable) + + // The id of the preview request. + IPC_STRUCT_MEMBER(int, preview_request_id) + + // Indicates whether the existing preview data needs to be cleared or not. + IPC_STRUCT_MEMBER(bool, clear_preview_data) +IPC_STRUCT_END() + +// Parameters to describe a rendered document. +IPC_STRUCT_BEGIN(PrintHostMsg_DidPreviewDocument_Params) + // A shared memory handle to metafile data. + IPC_STRUCT_MEMBER(base::SharedMemoryHandle, metafile_data_handle) + + // Size of metafile data. + IPC_STRUCT_MEMBER(uint32, data_size) + + // Cookie for the document to ensure correctness. + IPC_STRUCT_MEMBER(int, document_cookie) + + // Store the expected pages count. + IPC_STRUCT_MEMBER(int, expected_pages_count) + + // Whether the preview can be modified. + IPC_STRUCT_MEMBER(bool, modifiable) + + // The id of the preview request. + IPC_STRUCT_MEMBER(int, preview_request_id) +IPC_STRUCT_END() + // Messages sent from the browser to the renderer. @@ -198,6 +255,12 @@ IPC_MESSAGE_ROUTED2(PrintMsg_PrintPages, IPC_MESSAGE_ROUTED1(PrintMsg_PrintingDone, bool /* success */) +// Tells the render view to switch the CSS to print media type, renders every +// requested pages for print preview using the given |settings|. This gets +// called multiple times as the user updates settings. +IPC_MESSAGE_ROUTED1(PrintMsg_PrintPreview, + base::DictionaryValue /* settings */) + // Messages sent from the renderer to the browser. #if defined(OS_WIN) @@ -231,6 +294,14 @@ IPC_MESSAGE_ROUTED1(PrintHostMsg_DidPrintPage, IPC_SYNC_MESSAGE_ROUTED0_1(PrintHostMsg_GetDefaultPrintSettings, PrintMsg_Print_Params /* default_settings */) +// The renderer wants to update the current print settings with new +// |job_settings|. +IPC_SYNC_MESSAGE_ROUTED2_2(PrintHostMsg_UpdatePrintSettings, + int /* document_cookie */, + base::DictionaryValue /* job_settings */, + PrintMsg_PrintPages_Params /* current_settings */, + bool /* canceled */) + // It's the renderer that controls the printing process when it is generated // by javascript. This step is about showing UI to the user to select the // final print settings. The output parameter is the same as @@ -247,6 +318,20 @@ IPC_MESSAGE_ROUTED0(PrintHostMsg_ShowInvalidPrinterSettingsError) IPC_MESSAGE_ROUTED1(PrintHostMsg_PrintingFailed, int /* document cookie */) +// Notify the browser a print preview page has been rendered. +IPC_MESSAGE_ROUTED1(PrintHostMsg_DidPreviewPage, + PrintHostMsg_DidPreviewPage_Params /* params */) + +// Sends back to the browser the complete rendered document (non-draft mode, +// used for printing) that was requested by a PrintMsg_PrintPreview message. +// The memory handle in this message is already valid in the browser process. +IPC_MESSAGE_ROUTED1(PrintHostMsg_MetafileReadyForPrinting, + PrintHostMsg_DidPreviewDocument_Params /* params */) + +// Notify the browser the number of pages in the print preview document. +IPC_MESSAGE_ROUTED1(PrintHostMsg_DidGetPreviewPageCount, + PrintHostMsg_DidGetPreviewPageCount_Params /* params */) + #if defined(OS_WIN) // Tell the utility process to start rendering the given PDF into a metafile. diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper.cc b/chromium_src/chrome/renderer/printing/print_web_view_helper.cc index 60158f6c1d4c..82a7b54fc2c5 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper.cc +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper.cc @@ -650,6 +650,7 @@ bool PrintWebViewHelper::OnMessageReceived(const IPC::Message& message) { IPC_BEGIN_MESSAGE_MAP(PrintWebViewHelper, message) IPC_MESSAGE_HANDLER(PrintMsg_PrintPages, OnPrintPages) IPC_MESSAGE_HANDLER(PrintMsg_PrintingDone, OnPrintingDone) + IPC_MESSAGE_HANDLER(PrintMsg_PrintPreview, OnPrintPreview) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -712,6 +713,157 @@ void PrintWebViewHelper::OnPrintingDone(bool success) { DidFinishPrinting(success ? OK : FAIL_PRINT); } +void PrintWebViewHelper::OnPrintPreview(const base::DictionaryValue& settings) { + blink::WebLocalFrame* frame; + if (GetPrintFrame(&frame)) { + print_preview_context_.InitWithFrame(frame); + LOG(ERROR) << "OnPrintPreview1"; + if (!print_preview_context_.source_frame()) { + DidFinishPrinting(FAIL_PREVIEW); + return; + } + + LOG(ERROR) << "OnPrintPreview2"; + //SetPrintPagesParams(settings) + if (!UpdatePrintSettings(print_preview_context_.source_frame(), + print_preview_context_.source_node(), settings)) { + DidFinishPrinting(FAIL_PREVIEW); + return; + } + LOG(ERROR) << "OnPrintPreview3"; + is_print_ready_metafile_sent_ = false; + PrepareFrameForPreviewDocument(); + } +} + +void PrintWebViewHelper::PrepareFrameForPreviewDocument() { + reset_prep_frame_view_ = false; + + if (!print_pages_params_) { + DidFinishPrinting(FAIL_PREVIEW); + return; + } + + // Don't reset loading frame or WebKit will fail assert. Just retry when + // current selection is loaded. + if (prep_frame_view_ && prep_frame_view_->IsLoadingSelection()) { + reset_prep_frame_view_ = true; + return; + } + + const PrintMsg_Print_Params& print_params = print_pages_params_->params; + prep_frame_view_.reset(new PrepareFrameAndViewForPrint( + print_params, print_preview_context_.source_frame(), + print_preview_context_.source_node(), ignore_css_margins_)); + prep_frame_view_->CopySelectionIfNeeded( + render_view()->GetWebkitPreferences(), + base::Bind(&PrintWebViewHelper::OnFramePreparedForPreviewDocument, + base::Unretained(this))); +} + +void PrintWebViewHelper::OnFramePreparedForPreviewDocument() { + if (reset_prep_frame_view_) { + PrepareFrameForPreviewDocument(); + return; + } + DidFinishPrinting(CreatePreviewDocument() ? OK : FAIL_PREVIEW); +} + +bool PrintWebViewHelper::CreatePreviewDocument() { + if (!print_pages_params_) + return false; + + const PrintMsg_Print_Params& print_params = print_pages_params_->params; + const std::vector& pages = print_pages_params_->pages; + + if (!print_preview_context_.CreatePreviewDocument(prep_frame_view_.release(), + pages)) { + return false; + } + + PageSizeMargins default_page_layout; + ComputePageLayoutInPointsForCss(print_preview_context_.prepared_frame(), 0, + print_params, ignore_css_margins_, NULL, + &default_page_layout); + + //bool has_page_size_style = + //PrintingFrameHasPageSizeStyle(print_preview_context_.prepared_frame(), + //print_preview_context_.total_page_count()); + int dpi = GetDPI(&print_params); + + gfx::Rect printable_area_in_points( + ConvertUnit(print_params.printable_area.x(), dpi, kPointsPerInch), + ConvertUnit(print_params.printable_area.y(), dpi, kPointsPerInch), + ConvertUnit(print_params.printable_area.width(), dpi, kPointsPerInch), + ConvertUnit(print_params.printable_area.height(), dpi, kPointsPerInch)); + + + PrintHostMsg_DidGetPreviewPageCount_Params params; + params.page_count = print_preview_context_.total_page_count(); + params.is_modifiable = print_preview_context_.IsModifiable(); + params.document_cookie = print_params.document_cookie; + params.preview_request_id = print_params.preview_request_id; + params.clear_preview_data = print_preview_context_.generate_draft_pages(); + Send(new PrintHostMsg_DidGetPreviewPageCount(routing_id(), params)); + + while (!print_preview_context_.IsFinalPageRendered()) { + int page_number = print_preview_context_.GetNextPageNumber(); + DCHECK_GE(page_number, 0); + if (!RenderPreviewPage(page_number, print_params)) + return false; + + // We must call PrepareFrameAndViewForPrint::FinishPrinting() (by way of + // print_preview_context_.AllPagesRendered()) before calling + // FinalizePrintReadyDocument() when printing a PDF because the plugin + // code does not generate output until we call FinishPrinting(). We do not + // generate draft pages for PDFs, so IsFinalPageRendered() and + // IsLastPageOfPrintReadyMetafile() will be true in the same iteration of + // the loop. + if (print_preview_context_.IsFinalPageRendered()) + print_preview_context_.AllPagesRendered(); + + if (print_preview_context_.IsLastPageOfPrintReadyMetafile()) { + DCHECK(print_preview_context_.IsModifiable() || + print_preview_context_.IsFinalPageRendered()); + if (!FinalizePrintReadyDocument()) + return false; + } + } + print_preview_context_.Finished(); + return true; +} + +bool PrintWebViewHelper::FinalizePrintReadyDocument() { + DCHECK(!is_print_ready_metafile_sent_); + print_preview_context_.FinalizePrintReadyDocument(); + + // Get the size of the resulting metafile. + PdfMetafileSkia* metafile = print_preview_context_.metafile(); + uint32 buf_size = metafile->GetDataSize(); + DCHECK_GT(buf_size, 0u); + + PrintHostMsg_DidPreviewDocument_Params preview_params; + preview_params.data_size = buf_size; + preview_params.document_cookie = print_pages_params_->params.document_cookie; + preview_params.expected_pages_count = + print_preview_context_.total_page_count(); + preview_params.modifiable = print_preview_context_.IsModifiable(); + preview_params.preview_request_id = + print_pages_params_->params.preview_request_id; + + // Ask the browser to create the shared memory for us. + if (!CopyMetafileDataToSharedMem(metafile, + &(preview_params.metafile_data_handle))) { + LOG(ERROR) << "CopyMetafileDataToSharedMem failed"; + print_preview_context_.set_error(PREVIEW_ERROR_METAFILE_COPY_FAILED); + return false; + } + is_print_ready_metafile_sent_ = true; + + Send(new PrintHostMsg_MetafileReadyForPrinting(routing_id(), preview_params)); + return true; +} + void PrintWebViewHelper::PrintNode(const blink::WebNode& node) { if (node.isNull() || !node.document().frame()) { // This can occur when the context menu refers to an invalid WebNode. @@ -916,6 +1068,68 @@ bool PrintWebViewHelper::CalculateNumberOfPages(blink::WebLocalFrame* frame, return true; } +bool PrintWebViewHelper::UpdatePrintSettings( + blink::WebLocalFrame* frame, + const blink::WebNode& node, + const base::DictionaryValue& passed_job_settings) { + const base::DictionaryValue* job_settings = &passed_job_settings; + base::DictionaryValue modified_job_settings; + if (job_settings->empty()) { + if (!print_for_preview_) + print_preview_context_.set_error(PREVIEW_ERROR_BAD_SETTING); + return false; + } + + bool source_is_html = true; + if (print_for_preview_) { + if (!job_settings->GetBoolean(kSettingPreviewModifiable, &source_is_html)) { + NOTREACHED(); + } + } else { + source_is_html = !PrintingNodeOrPdfFrame(frame, node); + } + + if (print_for_preview_ || !source_is_html) { + modified_job_settings.MergeDictionary(job_settings); + modified_job_settings.SetBoolean(kSettingHeaderFooterEnabled, false); + modified_job_settings.SetInteger(kSettingMarginsType, NO_MARGINS); + job_settings = &modified_job_settings; + } + + // Send the cookie so that UpdatePrintSettings can reuse PrinterQuery when + // possible. + int cookie = + print_pages_params_ ? print_pages_params_->params.document_cookie : 0; + PrintMsg_PrintPages_Params settings; + bool canceled = false; + Send(new PrintHostMsg_UpdatePrintSettings(routing_id(), cookie, *job_settings, + &settings, &canceled)); + if (canceled) { + notify_browser_of_print_failure_ = false; + return false; + } + + if (!print_for_preview_) { + job_settings->GetInteger(kPreviewRequestID, + &settings.params.preview_request_id); + settings.params.print_to_pdf = true; + UpdateFrameMarginsCssInfo(*job_settings); + settings.params.print_scaling_option = + blink::WebPrintScalingOptionSourceSize; + } + + SetPrintPagesParams(settings); + + if (!PrintMsg_Print_Params_IsValid(settings.params)) { + if (!print_for_preview_) + print_preview_context_.set_error(PREVIEW_ERROR_INVALID_PRINTER_SETTINGS); + return false; + } + + return true; +} + + bool PrintWebViewHelper::GetPrintSettingsFromUser(blink::WebFrame* frame, const blink::WebNode& node, int expected_pages_count) { @@ -987,4 +1201,280 @@ void PrintWebViewHelper::SetPrintPagesParams( print_pages_params_.reset(new PrintMsg_PrintPages_Params(settings)); } +bool PrintWebViewHelper::PreviewPageRendered(int page_number, + PdfMetafileSkia* metafile) { + DCHECK_GE(page_number, FIRST_PAGE_INDEX); + + // For non-modifiable files, |metafile| should be NULL, so do not bother + // sending a message. If we don't generate draft metafiles, |metafile| is + // NULL. + if (!print_preview_context_.IsModifiable() || + !print_preview_context_.generate_draft_pages()) { + DCHECK(!metafile); + return true; + } + + if (!metafile) { + NOTREACHED(); + print_preview_context_.set_error( + PREVIEW_ERROR_PAGE_RENDERED_WITHOUT_METAFILE); + return false; + } + + PrintHostMsg_DidPreviewPage_Params preview_page_params; + // Get the size of the resulting metafile. + uint32 buf_size = metafile->GetDataSize(); + DCHECK_GT(buf_size, 0u); + if (!CopyMetafileDataToSharedMem( + metafile, &(preview_page_params.metafile_data_handle))) { + LOG(ERROR) << "CopyMetafileDataToSharedMem failed"; + print_preview_context_.set_error(PREVIEW_ERROR_METAFILE_COPY_FAILED); + return false; + } + preview_page_params.data_size = buf_size; + preview_page_params.page_number = page_number; + preview_page_params.preview_request_id = + print_pages_params_->params.preview_request_id; + + Send(new PrintHostMsg_DidPreviewPage(routing_id(), preview_page_params)); + return true; +} + +PrintWebViewHelper::PrintPreviewContext::PrintPreviewContext() + : total_page_count_(0), + current_page_index_(0), + generate_draft_pages_(true), + print_ready_metafile_page_count_(0), + error_(PREVIEW_ERROR_NONE), + state_(UNINITIALIZED) { +} + +PrintWebViewHelper::PrintPreviewContext::~PrintPreviewContext() { +} + +void PrintWebViewHelper::PrintPreviewContext::InitWithFrame( + blink::WebLocalFrame* web_frame) { + DCHECK(web_frame); + DCHECK(!IsRendering()); + state_ = INITIALIZED; + source_frame_.Reset(web_frame); + source_node_.reset(); +} + +void PrintWebViewHelper::PrintPreviewContext::InitWithNode( + const blink::WebNode& web_node) { + DCHECK(!web_node.isNull()); + DCHECK(web_node.document().frame()); + DCHECK(!IsRendering()); + state_ = INITIALIZED; + source_frame_.Reset(web_node.document().frame()); + source_node_ = web_node; +} + +void PrintWebViewHelper::PrintPreviewContext::OnPrintPreview() { + DCHECK_EQ(INITIALIZED, state_); + ClearContext(); +} + +bool PrintWebViewHelper::PrintPreviewContext::CreatePreviewDocument( + PrepareFrameAndViewForPrint* prepared_frame, + const std::vector& pages) { + DCHECK_EQ(INITIALIZED, state_); + state_ = RENDERING; + + // Need to make sure old object gets destroyed first. + prep_frame_view_.reset(prepared_frame); + prep_frame_view_->StartPrinting(); + + total_page_count_ = prep_frame_view_->GetExpectedPageCount(); + if (total_page_count_ == 0) { + LOG(ERROR) << "CreatePreviewDocument got 0 page count"; + set_error(PREVIEW_ERROR_ZERO_PAGES); + return false; + } + + metafile_.reset(new PdfMetafileSkia); + if (!metafile_->Init()) { + set_error(PREVIEW_ERROR_METAFILE_INIT_FAILED); + LOG(ERROR) << "PdfMetafileSkia Init failed"; + return false; + } + + current_page_index_ = 0; + pages_to_render_ = pages; + // Sort and make unique. + std::sort(pages_to_render_.begin(), pages_to_render_.end()); + pages_to_render_.resize( + std::unique(pages_to_render_.begin(), pages_to_render_.end()) - + pages_to_render_.begin()); + // Remove invalid pages. + pages_to_render_.resize(std::lower_bound(pages_to_render_.begin(), + pages_to_render_.end(), + total_page_count_) - + pages_to_render_.begin()); + print_ready_metafile_page_count_ = pages_to_render_.size(); + if (pages_to_render_.empty()) { + print_ready_metafile_page_count_ = total_page_count_; + // Render all pages. + for (int i = 0; i < total_page_count_; ++i) + pages_to_render_.push_back(i); + } else if (generate_draft_pages_) { + int pages_index = 0; + for (int i = 0; i < total_page_count_; ++i) { + if (pages_index < print_ready_metafile_page_count_ && + i == pages_to_render_[pages_index]) { + pages_index++; + continue; + } + pages_to_render_.push_back(i); + } + } + + document_render_time_ = base::TimeDelta(); + begin_time_ = base::TimeTicks::Now(); + + return true; +} + +void PrintWebViewHelper::PrintPreviewContext::RenderedPreviewPage( + const base::TimeDelta& page_time) { + DCHECK_EQ(RENDERING, state_); + document_render_time_ += page_time; + UMA_HISTOGRAM_TIMES("PrintPreview.RenderPDFPageTime", page_time); +} + +void PrintWebViewHelper::PrintPreviewContext::AllPagesRendered() { + DCHECK_EQ(RENDERING, state_); + state_ = DONE; + prep_frame_view_->FinishPrinting(); +} + +void PrintWebViewHelper::PrintPreviewContext::FinalizePrintReadyDocument() { + DCHECK(IsRendering()); + + base::TimeTicks begin_time = base::TimeTicks::Now(); + metafile_->FinishDocument(); + + if (print_ready_metafile_page_count_ <= 0) { + NOTREACHED(); + return; + } + + UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderToPDFTime", + document_render_time_); + base::TimeDelta total_time = + (base::TimeTicks::Now() - begin_time) + document_render_time_; + UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTime", + total_time); + UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTimeAvgPerPage", + total_time / pages_to_render_.size()); +} + +void PrintWebViewHelper::PrintPreviewContext::Finished() { + DCHECK_EQ(DONE, state_); + state_ = INITIALIZED; + ClearContext(); +} + +void PrintWebViewHelper::PrintPreviewContext::Failed(bool report_error) { + DCHECK(state_ == INITIALIZED || state_ == RENDERING); + state_ = INITIALIZED; + if (report_error) { + DCHECK_NE(PREVIEW_ERROR_NONE, error_); + UMA_HISTOGRAM_ENUMERATION("PrintPreview.RendererError", error_, + PREVIEW_ERROR_LAST_ENUM); + } + ClearContext(); +} + +int PrintWebViewHelper::PrintPreviewContext::GetNextPageNumber() { + DCHECK_EQ(RENDERING, state_); + if (IsFinalPageRendered()) + return -1; + return pages_to_render_[current_page_index_++]; +} + +bool PrintWebViewHelper::PrintPreviewContext::IsRendering() const { + return state_ == RENDERING || state_ == DONE; +} + +bool PrintWebViewHelper::PrintPreviewContext::IsModifiable() { + // The only kind of node we can print right now is a PDF node. + return !PrintingNodeOrPdfFrame(source_frame(), source_node_); +} + +bool PrintWebViewHelper::PrintPreviewContext::HasSelection() { + return IsModifiable() && source_frame()->hasSelection(); +} + +bool PrintWebViewHelper::PrintPreviewContext::IsLastPageOfPrintReadyMetafile() + const { + DCHECK(IsRendering()); + return current_page_index_ == print_ready_metafile_page_count_; +} + +bool PrintWebViewHelper::PrintPreviewContext::IsFinalPageRendered() const { + DCHECK(IsRendering()); + return static_cast(current_page_index_) == pages_to_render_.size(); +} + +void PrintWebViewHelper::PrintPreviewContext::set_generate_draft_pages( + bool generate_draft_pages) { + DCHECK_EQ(INITIALIZED, state_); + generate_draft_pages_ = generate_draft_pages; +} + +void PrintWebViewHelper::PrintPreviewContext::set_error( + enum PrintPreviewErrorBuckets error) { + error_ = error; +} + +blink::WebLocalFrame* PrintWebViewHelper::PrintPreviewContext::source_frame() { + DCHECK(state_ != UNINITIALIZED); + return source_frame_.GetFrame(); +} + +const blink::WebNode& + PrintWebViewHelper::PrintPreviewContext::source_node() const { + DCHECK(state_ != UNINITIALIZED); + return source_node_; +} + +blink::WebLocalFrame* +PrintWebViewHelper::PrintPreviewContext::prepared_frame() { + DCHECK(state_ != UNINITIALIZED); + return prep_frame_view_->frame(); +} + +const blink::WebNode& + PrintWebViewHelper::PrintPreviewContext::prepared_node() const { + DCHECK(state_ != UNINITIALIZED); + return prep_frame_view_->node(); +} + +int PrintWebViewHelper::PrintPreviewContext::total_page_count() const { + DCHECK(state_ != UNINITIALIZED); + return total_page_count_; +} + +bool PrintWebViewHelper::PrintPreviewContext::generate_draft_pages() const { + return generate_draft_pages_; +} + +PdfMetafileSkia* PrintWebViewHelper::PrintPreviewContext::metafile() { + DCHECK(IsRendering()); + return metafile_.get(); +} + +int PrintWebViewHelper::PrintPreviewContext::last_error() const { + return error_; +} + +void PrintWebViewHelper::PrintPreviewContext::ClearContext() { + prep_frame_view_.reset(); + metafile_.reset(); + pages_to_render_.clear(); + error_ = PREVIEW_ERROR_NONE; +} + } // namespace printing diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper.h b/chromium_src/chrome/renderer/printing/print_web_view_helper.h index 498a01b53da4..bfe9cb612d16 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper.h +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper.h @@ -76,6 +76,19 @@ class PrintWebViewHelper OK, FAIL_PRINT_INIT, FAIL_PRINT, + FAIL_PREVIEW, + }; + + enum PrintPreviewErrorBuckets { + PREVIEW_ERROR_NONE, // Always first. + PREVIEW_ERROR_BAD_SETTING, + PREVIEW_ERROR_METAFILE_COPY_FAILED, + PREVIEW_ERROR_METAFILE_INIT_FAILED, + PREVIEW_ERROR_ZERO_PAGES, + PREVIEW_ERROR_MAC_DRAFT_METAFILE_INIT_FAILED, + PREVIEW_ERROR_PAGE_RENDERED_WITHOUT_METAFILE, + PREVIEW_ERROR_INVALID_PRINTER_SETTINGS, + PREVIEW_ERROR_LAST_ENUM // Always last. }; // RenderViewObserver implementation. @@ -88,6 +101,8 @@ class PrintWebViewHelper void OnPrintPages(bool silent, bool print_background); void OnPrintingDone(bool success); #endif // !DISABLE_BASIC_PRINTING + void OnPrintPreview(const base::DictionaryValue& settings); + // Get |page_size| and |content_area| information from // |page_layout_in_points|. @@ -99,6 +114,24 @@ class PrintWebViewHelper // Update |ignore_css_margins_| based on settings. void UpdateFrameMarginsCssInfo(const base::DictionaryValue& settings); + // Prepare frame for creating preview document. + void PrepareFrameForPreviewDocument(); + + // Continue creating preview document. + void OnFramePreparedForPreviewDocument(); + + // Finalize the print ready preview document. + bool FinalizePrintReadyDocument(); + + // Renders a print preview page. |page_number| is 0-based. + // Returns true if print preview should continue, false on failure. + bool RenderPreviewPage(int page_number, + const PrintMsg_Print_Params& print_params); + + + // Initialize the print preview document. + bool CreatePreviewDocument(); + // Main printing code ------------------------------------------------------- void Print(blink::WebLocalFrame* frame, @@ -120,6 +153,14 @@ class PrintWebViewHelper const blink::WebNode& node, int* number_of_pages); + // Update the current print settings with new |passed_job_settings|. + // |passed_job_settings| dictionary contains print job details such as printer + // name, number of copies, page range, etc. + bool UpdatePrintSettings(blink::WebLocalFrame* frame, + const blink::WebNode& node, + const base::DictionaryValue& passed_job_settings); + + // Get final print settings from the user. // Return false if the user cancels or on error. bool GetPrintSettingsFromUser(blink::WebFrame* frame, @@ -193,6 +234,13 @@ class PrintWebViewHelper // Script Initiated Printing ------------------------------------------------ + // Notifies the browser a print preview page has been rendered. + // |page_number| is 0-based. + // For a valid |page_number| with modifiable content, + // |metafile| is the rendered page. Otherwise |metafile| is NULL. + // Returns true if print preview should continue, false on failure. + bool PreviewPageRendered(int page_number, PdfMetafileSkia* metafile); + void SetPrintPagesParams(const PrintMsg_PrintPages_Params& settings); // WebView used only to print the selection. @@ -213,10 +261,121 @@ class PrintWebViewHelper // True, when printing from print preview. bool print_for_preview_; + // Keeps track of the state of print preview between messages. + // TODO(vitalybuka): Create PrintPreviewContext when needed and delete after + // use. Now it's interaction with various messages is confusing. + class PrintPreviewContext { + public: + PrintPreviewContext(); + ~PrintPreviewContext(); + + // Initializes the print preview context. Need to be called to set + // the |web_frame| / |web_node| to generate the print preview for. + void InitWithFrame(blink::WebLocalFrame* web_frame); + void InitWithNode(const blink::WebNode& web_node); + + // Does bookkeeping at the beginning of print preview. + void OnPrintPreview(); + + // Create the print preview document. |pages| is empty to print all pages. + // Takes ownership of |prepared_frame|. + bool CreatePreviewDocument(PrepareFrameAndViewForPrint* prepared_frame, + const std::vector& pages); + + // Called after a page gets rendered. |page_time| is how long the + // rendering took. + void RenderedPreviewPage(const base::TimeDelta& page_time); + + // Updates the print preview context when the required pages are rendered. + void AllPagesRendered(); + + // Finalizes the print ready preview document. + void FinalizePrintReadyDocument(); + + // Cleanup after print preview finishes. + void Finished(); + + // Cleanup after print preview fails. + void Failed(bool report_error); + + // Helper functions + int GetNextPageNumber(); + bool IsRendering() const; + bool IsModifiable(); + bool HasSelection(); + bool IsLastPageOfPrintReadyMetafile() const; + bool IsFinalPageRendered() const; + + // Setters + void set_generate_draft_pages(bool generate_draft_pages); + void set_error(enum PrintPreviewErrorBuckets error); + + // Getters + // Original frame for which preview was requested. + blink::WebLocalFrame* source_frame(); + // Original node for which preview was requested. + const blink::WebNode& source_node() const; + + // Frame to be use to render preview. May be the same as source_frame(), or + // generated from it, e.g. copy of selected block. + blink::WebLocalFrame* prepared_frame(); + // Node to be use to render preview. May be the same as source_node(), or + // generated from it, e.g. copy of selected block. + const blink::WebNode& prepared_node() const; + + int total_page_count() const; + bool generate_draft_pages() const; + PdfMetafileSkia* metafile(); + int last_error() const; + + private: + enum State { + UNINITIALIZED, // Not ready to render. + INITIALIZED, // Ready to render. + RENDERING, // Rendering. + DONE // Finished rendering. + }; + + // Reset some of the internal rendering context. + void ClearContext(); + + // Specifies what to render for print preview. + FrameReference source_frame_; + blink::WebNode source_node_; + + scoped_ptr prep_frame_view_; + scoped_ptr metafile_; + + // Total page count in the renderer. + int total_page_count_; + + // The current page to render. + int current_page_index_; + + // List of page indices that need to be rendered. + std::vector pages_to_render_; + + // True, when draft pages needs to be generated. + bool generate_draft_pages_; + + // Specifies the total number of pages in the print ready metafile. + int print_ready_metafile_page_count_; + + base::TimeDelta document_render_time_; + base::TimeTicks begin_time_; + + enum PrintPreviewErrorBuckets error_; + + State state_; + }; + + bool print_node_in_progress_; bool is_loading_; bool is_scripted_preview_delayed_; + PrintPreviewContext print_preview_context_; + // Used to fix a race condition where the source is a PDF and print preview // hangs because RequestPrintPreview is called before DidStopLoading() is // called. This is a store for the RequestPrintPreview() call and its diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc b/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc index f98ee5097cca..dcd388fd1111 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper_pdf_win.cc @@ -21,7 +21,6 @@ namespace printing { using blink::WebFrame; -#if 0 bool PrintWebViewHelper::RenderPreviewPage( int page_number, const PrintMsg_Print_Params& print_params) { @@ -53,7 +52,6 @@ bool PrintWebViewHelper::RenderPreviewPage( } return PreviewPageRendered(page_number, draft_metafile.get()); } -#endif bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame, int page_count) { diff --git a/filenames.gypi b/filenames.gypi index 6ece2ba634c7..de1d04174648 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -314,6 +314,8 @@ 'chromium_src/chrome/browser/printing/printer_query.h', 'chromium_src/chrome/browser/printing/printing_message_filter.cc', 'chromium_src/chrome/browser/printing/printing_message_filter.h', + 'chromium_src/chrome/browser/printing/print_preview_message_handler.cc', + 'chromium_src/chrome/browser/printing/print_preview_message_handler.h', 'chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc', 'chromium_src/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.h', 'chromium_src/chrome/browser/renderer_host/pepper/pepper_broker_message_filter.cc', From 9cf9229308bc69e15d3b75e1d71a10b9e6627a93 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Sun, 31 May 2015 11:07:26 +0800 Subject: [PATCH 03/28] Write PDF file in FILE thread. --- .../printing/print_preview_message_handler.cc | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc index 6cc47e90876f..c5b59547599b 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc @@ -60,6 +60,15 @@ base::RefCountedBytes* GetDataFromHandle(base::SharedMemoryHandle handle, return base::RefCountedBytes::TakeVector(&data); } +void PrintToPdfCallback(const scoped_refptr& data, + const base::FilePath& save_path) { + printing::PdfMetafileSkia metafile; + metafile.InitFromData(static_cast(data->front()), data->size()); + base::File file(save_path, + base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); + metafile.SaveTo(&file); +} + } // namespace namespace printing { @@ -116,11 +125,11 @@ void PrintPreviewMessageHandler::OnMetafileReadyForPrinting( 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(data->front()), data->size()); - base::File file(save_path, - base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); - metafile.SaveTo(&file); + BrowserThread::PostTask(BrowserThread::FILE, + FROM_HERE, + base::Bind(&PrintToPdfCallback, + data, + save_path)); } //void PrintPreviewMessageHandler::OnPrintPreviewFailed(int document_cookie) { From ce8bbb689c142d145763c31f9e6915385bcb3263 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Sun, 31 May 2015 14:52:41 +0800 Subject: [PATCH 04/28] Add options to custom print settings in printToPDF API. --- atom/browser/api/atom_api_window.cc | 10 +++++-- atom/browser/api/atom_api_window.h | 2 +- atom/browser/native_window.cc | 4 +-- atom/browser/native_window.h | 2 +- .../printing/print_preview_message_handler.cc | 26 ++++++++++++++++--- .../printing/print_preview_message_handler.h | 7 +++-- 6 files changed, 40 insertions(+), 11 deletions(-) diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 00a0bb464089..66f17029bd54 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -16,6 +16,7 @@ #include "native_mate/callback.h" #include "native_mate/constructor.h" #include "native_mate/dictionary.h" +#include "printing/print_job_constants.h" #include "ui/gfx/geometry/rect.h" #include "atom/common/node_includes.h" @@ -430,8 +431,13 @@ void Window::Print(mate::Arguments* args) { window_->Print(settings.silent, settings.print_background); } -void Window::PrintToPDF() { - window_->PrintToPDF(); +void Window::PrintToPDF(mate::Arguments* args) { + mate::Dictionary options; + if (args->Length() == 1 && !args->GetNext(&options)) { + args->ThrowError(); + return; + } + window_->PrintToPDF(options); } void Window::SetProgressBar(double progress) { diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index 606fda9f7dc3..828ab2ab9014 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -132,7 +132,7 @@ class Window : public mate::EventEmitter, bool IsDocumentEdited(); void CapturePage(mate::Arguments* args); void Print(mate::Arguments* args); - void PrintToPDF(); + void PrintToPDF(mate::Arguments* args); void SetProgressBar(double progress); void SetOverlayIcon(const gfx::Image& overlay, const std::string& description); diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 9b922dc9b5b0..f7616f423666 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -265,9 +265,9 @@ void NativeWindow::Print(bool silent, bool print_background) { PrintNow(silent, print_background); } -void NativeWindow::PrintToPDF() { +void NativeWindow::PrintToPDF(const mate::Dictionary& options) { printing::PrintPreviewMessageHandler::FromWebContents(GetWebContents())-> - HandleGetPreview(NULL); + HandleGetPreview(options); } void NativeWindow::ShowDefinitionForSelection() { diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index 5c99a2c117b5..dd10dd1229f2 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -158,7 +158,7 @@ class NativeWindow : public CommonWebContentsDelegate, virtual void Print(bool silent, bool print_background); // Print current page as PDF. - virtual void PrintToPDF(); + virtual void PrintToPDF(const mate::Dictionary& options); // Show popup dictionary. virtual void ShowDefinitionForSelection(); diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc index c5b59547599b..bb960b2ef75e 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc @@ -199,7 +199,8 @@ bool PrintPreviewMessageHandler::OnMessageReceived( return handled; } -void PrintPreviewMessageHandler::HandleGetPreview(const base::ListValue* args) { +void PrintPreviewMessageHandler::HandleGetPreview( + const mate::Dictionary& options) { static int request_id = 0; request_id++; // A simulated Chromium print preivew setting. @@ -212,7 +213,7 @@ void PrintPreviewMessageHandler::HandleGetPreview(const base::ListValue* args) { \"width_microns\":210000, \ \"custom_display_name\":\"A4\" \ }, \ - \"landscape\":true, \ + \"landscape\":false, \ \"color\":2, \ \"headerFooterEnabled\":false, \ \"marginsType\":0, \ @@ -229,7 +230,7 @@ void PrintPreviewMessageHandler::HandleGetPreview(const base::ListValue* args) { \"duplex\":0, \ \"copies\":1, \ \"collate\":true, \ - \"shouldPrintBackgrounds\":true, \ + \"shouldPrintBackgrounds\":false, \ \"shouldPrintSelectionOnly\":false \ }"; @@ -237,7 +238,26 @@ void PrintPreviewMessageHandler::HandleGetPreview(const base::ListValue* args) { static_cast( base::JSONReader::Read(setting_json_str))); settings->SetInteger(printing::kPreviewRequestID, request_id); + // Default Print PDF settings: + int margins_type = 0; // DEFAULT_MARGINS + bool print_background = false; + bool print_selection_only = false; + bool is_landscape = false; // layout: true for portrait, false for landscape + if (!options.IsEmpty()) { + options.Get(printing::kSettingMarginsType, &margins_type); + options.Get(printing::kSettingShouldPrintBackgrounds, &print_background); + options.Get(printing::kSettingShouldPrintSelectionOnly, + &print_selection_only); + std::string layout; + options.Get("layout", &is_landscape); + } + settings->SetInteger(printing::kSettingMarginsType, margins_type); + settings->SetBoolean(printing::kSettingShouldPrintBackgrounds, + print_background); + settings->SetBoolean(printing::kSettingShouldPrintSelectionOnly, + print_selection_only); + settings->SetBoolean(printing::kSettingLandscape, is_landscape); LOG(ERROR) << "Print preview request start"; content::RenderViewHost* rvh = web_contents()->GetRenderViewHost(); rvh->Send(new PrintMsg_PrintPreview(rvh->GetRoutingID(), *settings)); diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.h b/chromium_src/chrome/browser/printing/print_preview_message_handler.h index 8f9f1b4ed230..38943b01b80a 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.h +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.h @@ -17,6 +17,10 @@ namespace content { class WebContents; } +namespace mate { +class Dictionary; +} + namespace gfx { class Rect; } @@ -37,8 +41,7 @@ class PrintPreviewMessageHandler // Asks the initiator renderer to generate a preview. First element of |args| // is a job settings JSON string. - void HandleGetPreview(const base::ListValue* args); - + void HandleGetPreview(const mate::Dictionary& options); private: explicit PrintPreviewMessageHandler(content::WebContents* web_contents); friend class content::WebContentsUserData; From 8572ccb80733bab172e64d5c06814acc7d1b27ea Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Mon, 1 Jun 2015 10:37:27 +0800 Subject: [PATCH 05/28] Add callback function in printToPDF API. --- atom/browser/api/atom_api_window.cc | 8 ++-- atom/browser/native_window.cc | 5 ++- atom/browser/native_window.h | 4 +- .../printing/print_preview_message_handler.cc | 43 +++++++++++++------ .../printing/print_preview_message_handler.h | 20 ++++++++- 5 files changed, 61 insertions(+), 19 deletions(-) diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 66f17029bd54..8872a0e7f6ca 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -16,7 +16,6 @@ #include "native_mate/callback.h" #include "native_mate/constructor.h" #include "native_mate/dictionary.h" -#include "printing/print_job_constants.h" #include "ui/gfx/geometry/rect.h" #include "atom/common/node_includes.h" @@ -433,11 +432,14 @@ void Window::Print(mate::Arguments* args) { void Window::PrintToPDF(mate::Arguments* args) { mate::Dictionary options; - if (args->Length() == 1 && !args->GetNext(&options)) { + base::Callback callback; + if (!(args->Length() == 1 && !args->GetNext(&callback)) && + !(args->Length() == 2 && args->GetNext(&options) + && args->GetNext(&callback))) { args->ThrowError(); return; } - window_->PrintToPDF(options); + window_->PrintToPDF(options, callback); } void Window::SetProgressBar(double progress) { diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index f7616f423666..2edf8906d6c2 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -265,9 +265,10 @@ void NativeWindow::Print(bool silent, bool print_background) { PrintNow(silent, print_background); } -void NativeWindow::PrintToPDF(const mate::Dictionary& options) { +void NativeWindow::PrintToPDF(const mate::Dictionary& options, + const PrintToPDFCallback& callback) { printing::PrintPreviewMessageHandler::FromWebContents(GetWebContents())-> - HandleGetPreview(options); + HandleGetPreview(options, callback); } void NativeWindow::ShowDefinitionForSelection() { diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index dd10dd1229f2..78187bc8d458 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -55,6 +55,7 @@ class NativeWindow : public CommonWebContentsDelegate, public content::NotificationObserver { public: typedef base::Callback CapturePageCallback; + typedef base::Callback PrintToPDFCallback; class DialogScope { public: @@ -158,7 +159,8 @@ class NativeWindow : public CommonWebContentsDelegate, virtual void Print(bool silent, bool print_background); // Print current page as PDF. - virtual void PrintToPDF(const mate::Dictionary& options); + virtual void PrintToPDF(const mate::Dictionary& options, + const PrintToPDFCallback& callback); // Show popup dictionary. virtual void ShowDefinitionForSelection(); diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc index bb960b2ef75e..36befec47915 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc @@ -60,19 +60,23 @@ base::RefCountedBytes* GetDataFromHandle(base::SharedMemoryHandle handle, return base::RefCountedBytes::TakeVector(&data); } -void PrintToPdfCallback(const scoped_refptr& data, - const base::FilePath& save_path) { +printing::PrintPreviewMessageHandler::PrintPDFResult +SavePDF(const scoped_refptr& data, + const base::FilePath& save_path) { printing::PdfMetafileSkia metafile; metafile.InitFromData(static_cast(data->front()), data->size()); base::File file(save_path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); - metafile.SaveTo(&file); + return metafile.SaveTo(&file)? + printing::PrintPreviewMessageHandler::SUCCESS : + printing::PrintPreviewMessageHandler::FAIL_SAVEFILE; } } // namespace namespace printing { + PrintPreviewMessageHandler::PrintPreviewMessageHandler( WebContents* web_contents) : content::WebContentsObserver(web_contents) { @@ -122,14 +126,19 @@ void PrintPreviewMessageHandler::OnMetafileReadyForPrinting( 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); - BrowserThread::PostTask(BrowserThread::FILE, - FROM_HERE, - base::Bind(&PrintToPdfCallback, - data, - save_path)); + if (!file_dialog::ShowSaveDialog(window, "Save As", + base::FilePath(FILE_PATH_LITERAL("print.pdf")), + file_dialog::Filters(), &save_path)) { // Users cancel dialog. + RunPrintToPDFCallback(params.preview_request_id, FAIL_CANCEL); + return; + } + BrowserThread::PostTaskAndReplyWithResult( + BrowserThread::FILE, + FROM_HERE, + base::Bind(&SavePDF, data, save_path), + base::Bind(&PrintPreviewMessageHandler::RunPrintToPDFCallback, + base::Unretained(this), + params.preview_request_id)); } //void PrintPreviewMessageHandler::OnPrintPreviewFailed(int document_cookie) { @@ -200,7 +209,8 @@ bool PrintPreviewMessageHandler::OnMessageReceived( } void PrintPreviewMessageHandler::HandleGetPreview( - const mate::Dictionary& options) { + const mate::Dictionary& options, + const atom::NativeWindow::PrintToPDFCallback& callback) { static int request_id = 0; request_id++; // A simulated Chromium print preivew setting. @@ -238,6 +248,9 @@ void PrintPreviewMessageHandler::HandleGetPreview( static_cast( base::JSONReader::Read(setting_json_str))); settings->SetInteger(printing::kPreviewRequestID, request_id); + print_to_pdf_callback_map_[request_id] = callback; + + // Default Print PDF settings: int margins_type = 0; // DEFAULT_MARGINS bool print_background = false; @@ -263,4 +276,10 @@ void PrintPreviewMessageHandler::HandleGetPreview( rvh->Send(new PrintMsg_PrintPreview(rvh->GetRoutingID(), *settings)); } +void PrintPreviewMessageHandler::RunPrintToPDFCallback( + int request_id, PrintPDFResult result) { + print_to_pdf_callback_map_[request_id].Run(static_cast(result)); + print_to_pdf_callback_map_.erase(request_id); +} + } // namespace printing diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.h b/chromium_src/chrome/browser/printing/print_preview_message_handler.h index 38943b01b80a..5594a41f2db1 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.h +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.h @@ -5,6 +5,9 @@ #ifndef CHROME_BROWSER_PRINTING_PRINT_PREVIEW_MESSAGE_HANDLER_H_ #define CHROME_BROWSER_PRINTING_PRINT_PREVIEW_MESSAGE_HANDLER_H_ +#include + +#include "atom/browser/native_window.h" #include "base/compiler_specific.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_user_data.h" @@ -34,6 +37,13 @@ class PrintPreviewMessageHandler : public content::WebContentsObserver, public content::WebContentsUserData { public: + enum PrintPDFResult { + SUCCESS, + FAIL_PREVIEW, + FAIL_SAVEFILE, + FAIL_CANCEL, + }; + ~PrintPreviewMessageHandler() override; // content::WebContentsObserver implementation. @@ -41,8 +51,12 @@ class PrintPreviewMessageHandler // Asks the initiator renderer to generate a preview. First element of |args| // is a job settings JSON string. - void HandleGetPreview(const mate::Dictionary& options); + void HandleGetPreview(const mate::Dictionary& options, + const atom::NativeWindow::PrintToPDFCallback& callback); + private: + typedef std::map PrintToPDFCallbackMap; + explicit PrintPreviewMessageHandler(content::WebContents* web_contents); friend class content::WebContentsUserData; @@ -65,6 +79,10 @@ class PrintPreviewMessageHandler //void OnSetOptionsFromDocument( //const PrintHostMsg_SetOptionsFromDocument_Params& params); + void RunPrintToPDFCallback(int request_id, PrintPDFResult result); + + PrintToPDFCallbackMap print_to_pdf_callback_map_; + DISALLOW_COPY_AND_ASSIGN(PrintPreviewMessageHandler); }; From cef177abc460cecd4fc9004f7f9497a222c1e13d Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Mon, 1 Jun 2015 11:08:40 +0800 Subject: [PATCH 06/28] Add preview failed error. --- .../printing/print_preview_message_handler.cc | 17 +++++++---------- .../printing/print_preview_message_handler.h | 2 +- chromium_src/chrome/common/print_messages.h | 3 +++ .../renderer/printing/print_web_view_helper.cc | 10 +++++++++- 4 files changed, 20 insertions(+), 12 deletions(-) diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc index 36befec47915..0a3ae97afd60 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc @@ -141,14 +141,11 @@ void PrintPreviewMessageHandler::OnMetafileReadyForPrinting( params.preview_request_id)); } -//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::OnPrintPreviewFailed(int document_cookie, + int request_id) { + StopWorker(document_cookie); + RunPrintToPDFCallback(request_id, FAIL_PREVIEW); +} //void PrintPreviewMessageHandler::OnDidGetDefaultPageLayout( //const PageSizeMargins& page_layout_in_points, @@ -193,8 +190,8 @@ bool PrintPreviewMessageHandler::OnMessageReceived( OnDidPreviewPage) IPC_MESSAGE_HANDLER(PrintHostMsg_MetafileReadyForPrinting, OnMetafileReadyForPrinting) - //IPC_MESSAGE_HANDLER(PrintHostMsg_PrintPreviewFailed, - //OnPrintPreviewFailed) + IPC_MESSAGE_HANDLER(PrintHostMsg_PrintPreviewFailed, + OnPrintPreviewFailed) //IPC_MESSAGE_HANDLER(PrintHostMsg_DidGetDefaultPageLayout, //OnDidGetDefaultPageLayout) //IPC_MESSAGE_HANDLER(PrintHostMsg_PrintPreviewCancelled, diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.h b/chromium_src/chrome/browser/printing/print_preview_message_handler.h index 5594a41f2db1..f4298fb6b2fc 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.h +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.h @@ -73,7 +73,7 @@ class PrintPreviewMessageHandler void OnDidPreviewPage(const PrintHostMsg_DidPreviewPage_Params& params); void OnMetafileReadyForPrinting( const PrintHostMsg_DidPreviewDocument_Params& params); - //void OnPrintPreviewFailed(int document_cookie); + void OnPrintPreviewFailed(int document_cookie, int request_id); //void OnPrintPreviewCancelled(int document_cookie); //void OnInvalidPrinterSettings(int document_cookie); //void OnSetOptionsFromDocument( diff --git a/chromium_src/chrome/common/print_messages.h b/chromium_src/chrome/common/print_messages.h index 2e6d23771676..fc9c1d493509 100644 --- a/chromium_src/chrome/common/print_messages.h +++ b/chromium_src/chrome/common/print_messages.h @@ -332,6 +332,9 @@ IPC_MESSAGE_ROUTED1(PrintHostMsg_MetafileReadyForPrinting, IPC_MESSAGE_ROUTED1(PrintHostMsg_DidGetPreviewPageCount, PrintHostMsg_DidGetPreviewPageCount_Params /* params */) +IPC_MESSAGE_ROUTED2(PrintHostMsg_PrintPreviewFailed, + int /* document cookie */, + int /* request_id */); #if defined(OS_WIN) // Tell the utility process to start rendering the given PDF into a metafile. diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper.cc b/chromium_src/chrome/renderer/printing/print_web_view_helper.cc index 82a7b54fc2c5..550735f709b5 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper.cc +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper.cc @@ -724,7 +724,6 @@ void PrintWebViewHelper::OnPrintPreview(const base::DictionaryValue& settings) { } LOG(ERROR) << "OnPrintPreview2"; - //SetPrintPagesParams(settings) if (!UpdatePrintSettings(print_preview_context_.source_frame(), print_preview_context_.source_node(), settings)) { DidFinishPrinting(FAIL_PREVIEW); @@ -938,6 +937,15 @@ void PrintWebViewHelper::DidFinishPrinting(PrintingResult result) { Send(new PrintHostMsg_PrintingFailed(routing_id(), cookie)); } break; + + case FAIL_PREVIEW: + LOG(ERROR) << "PREVIEW FAILED."; + if (print_pages_params_) { + Send(new PrintHostMsg_PrintPreviewFailed(routing_id(), + print_pages_params_->params.document_cookie, + print_pages_params_->params.preview_request_id)); + } + break; } prep_frame_view_.reset(); print_pages_params_.reset(); From 600077996c2607dd6b416f0e488c3876fa9d270e Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Mon, 1 Jun 2015 11:45:03 +0800 Subject: [PATCH 07/28] Fix a `landscape` option error. --- .../chrome/browser/printing/print_preview_message_handler.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc index 0a3ae97afd60..ee47742c687a 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc @@ -252,15 +252,14 @@ void PrintPreviewMessageHandler::HandleGetPreview( int margins_type = 0; // DEFAULT_MARGINS bool print_background = false; bool print_selection_only = false; - bool is_landscape = false; // layout: true for portrait, false for landscape + bool is_landscape = false; if (!options.IsEmpty()) { options.Get(printing::kSettingMarginsType, &margins_type); options.Get(printing::kSettingShouldPrintBackgrounds, &print_background); options.Get(printing::kSettingShouldPrintSelectionOnly, &print_selection_only); - std::string layout; - options.Get("layout", &is_landscape); + options.Get(printing::kSettingLandscape, &is_landscape); } settings->SetInteger(printing::kSettingMarginsType, margins_type); settings->SetBoolean(printing::kSettingShouldPrintBackgrounds, From bf5d448e37086aba4e410a579cfc415636a59af5 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Mon, 1 Jun 2015 11:45:43 +0800 Subject: [PATCH 08/28] :memo: Add BrowserWindow.printToPDF API docs. --- docs/api/browser-window.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 11ac53096038..58e6fa73e35c 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -571,6 +571,32 @@ Calling `window.print()` in web page is equivalent to call doesn't need print feature, you can safely remove `pdf.dll` in saving binary size. +### BrowserWindow.printToPDF([options], callback) + +* `options` Object + * `marginsType` Integer - Specify the type of margins to use + * 0 - default + * 1 - none + * 2 - minimum + * `shouldPrintBackgrounds` Boolean - Whether to print CSS backgrounds. + * `shouldPrintSelectionOnly` Boolean - Whether to print selection only. + * `landscape` Boolean - `true` for landscape, `false` for portrait. + +* `callback` Function - `function(statusCode) {}` + * `statusCode` Integer + * 0 - Success. + * 1 - Fail to generate PDF file on renderer part. + * 2 - Fail to save PDF file on local disk. + * 3 - Users cancel the prompted save file dialog. + +Prints windows' web page as PDF with Chromium's preview printing custom +settings. The API will prompt a SaveDialog to allow user custom the file path +for saving the generated PDF file on disk. + +By default, the options will be +`{marginsType:0, shouldPrintBackgrounds:false, shouldPrintSelectionOnly:false, + landscape:false}`. + ### BrowserWindow.loadUrl(url, [options]) Same with `webContents.loadUrl(url, [options])`. From 68005f9ad4693bf761f2a983014ff71390107ee3 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Mon, 1 Jun 2015 14:14:33 +0800 Subject: [PATCH 09/28] Fix OS X compilation error. --- .../printing/print_web_view_helper_mac.mm | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm b/chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm index 93fd06464b37..0785e30a9cfb 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm @@ -50,6 +50,47 @@ void PrintWebViewHelper::PrintPageInternal( Send(new PrintHostMsg_DidPrintPage(routing_id(), page_params)); } +bool PrintWebViewHelper::RenderPreviewPage( + int page_number, + const PrintMsg_Print_Params& print_params) { + PrintMsg_Print_Params printParams = print_params; + scoped_ptr draft_metafile; + PdfMetafileSkia* initial_render_metafile = print_preview_context_.metafile(); + + bool render_to_draft = print_preview_context_.IsModifiable() && + is_print_ready_metafile_sent_; + + if (render_to_draft) { + draft_metafile.reset(new PdfMetafileSkia()); + if (!draft_metafile->Init()) { + print_preview_context_.set_error( + PREVIEW_ERROR_MAC_DRAFT_METAFILE_INIT_FAILED); + LOG(ERROR) << "Draft PdfMetafileSkia Init failed"; + return false; + } + initial_render_metafile = draft_metafile.get(); + } + + base::TimeTicks begin_time = base::TimeTicks::Now(); + gfx::Size page_size; + RenderPage(printParams, page_number, print_preview_context_.prepared_frame(), + true, initial_render_metafile, &page_size, NULL); + print_preview_context_.RenderedPreviewPage( + base::TimeTicks::Now() - begin_time); + + if (draft_metafile.get()) { + draft_metafile->FinishDocument(); + } else { + if (print_preview_context_.IsModifiable() && + print_preview_context_.generate_draft_pages()) { + DCHECK(!draft_metafile.get()); + draft_metafile = + print_preview_context_.metafile()->GetMetafileForCurrentPage(); + } + } + return PreviewPageRendered(page_number, draft_metafile.get()); +} + void PrintWebViewHelper::RenderPage(const PrintMsg_Print_Params& params, int page_number, WebFrame* frame, From 36fa4da25217b6248ffe87e4b1fc0f84e231482f Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Mon, 1 Jun 2015 14:58:15 +0800 Subject: [PATCH 10/28] Fix Linux compilation error. --- .../printing/print_web_view_helper_linux.cc | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc b/chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc index 38bd9114d244..82d7779d0266 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc @@ -24,6 +24,36 @@ namespace printing { using blink::WebFrame; +bool PrintWebViewHelper::RenderPreviewPage( + int page_number, + const PrintMsg_Print_Params& print_params) { + PrintMsg_PrintPage_Params page_params; + page_params.params = print_params; + page_params.page_number = page_number; + scoped_ptr draft_metafile; + PdfMetafileSkia* initial_render_metafile = print_preview_context_.metafile(); + if (print_preview_context_.IsModifiable() && is_print_ready_metafile_sent_) { + draft_metafile.reset(new PdfMetafileSkia); + initial_render_metafile = draft_metafile.get(); + } + + base::TimeTicks begin_time = base::TimeTicks::Now(); + PrintPageInternal(page_params, + print_preview_context_.prepared_frame(), + initial_render_metafile); + print_preview_context_.RenderedPreviewPage( + base::TimeTicks::Now() - begin_time); + if (draft_metafile.get()) { + draft_metafile->FinishDocument(); + } else if (print_preview_context_.IsModifiable() && + print_preview_context_.generate_draft_pages()) { + DCHECK(!draft_metafile.get()); + draft_metafile = + print_preview_context_.metafile()->GetMetafileForCurrentPage(); + } + return PreviewPageRendered(page_number, draft_metafile.get()); +} + bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame, int page_count) { PdfMetafileSkia metafile; From 10da361db12a5898e9f233536544f0d6770ef5f8 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Mon, 1 Jun 2015 17:08:15 +0800 Subject: [PATCH 11/28] Fix a type error in checking function options. --- atom/browser/api/atom_api_window.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 8872a0e7f6ca..7ab03181993c 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -433,7 +433,7 @@ void Window::Print(mate::Arguments* args) { void Window::PrintToPDF(mate::Arguments* args) { mate::Dictionary options; base::Callback callback; - if (!(args->Length() == 1 && !args->GetNext(&callback)) && + if (!(args->Length() == 1 && args->GetNext(&callback)) && !(args->Length() == 2 && args->GetNext(&options) && args->GetNext(&callback))) { args->ThrowError(); From 2597ded985b2427956496c6b034819e1f33665fe Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Mon, 1 Jun 2015 18:00:00 +0800 Subject: [PATCH 12/28] Cleanup. --- atom/browser/api/atom_api_window.cc | 2 +- atom/browser/native_window.cc | 2 +- .../printing/print_preview_message_handler.cc | 58 ++----------------- .../printing/print_preview_message_handler.h | 20 ++----- .../printing/print_web_view_helper.cc | 3 - 5 files changed, 13 insertions(+), 72 deletions(-) diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 7ab03181993c..4b6ab9c95422 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -421,7 +421,7 @@ void Window::CapturePage(mate::Arguments* args) { } void Window::Print(mate::Arguments* args) { - PrintSettings settings = { false, false };; + PrintSettings settings = { false, false }; if (args->Length() == 1 && !args->GetNext(&settings)) { args->ThrowError(); return; diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 2edf8906d6c2..e1cdab59471b 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -268,7 +268,7 @@ void NativeWindow::Print(bool silent, bool print_background) { void NativeWindow::PrintToPDF(const mate::Dictionary& options, const PrintToPDFCallback& callback) { printing::PrintPreviewMessageHandler::FromWebContents(GetWebContents())-> - HandleGetPreview(options, callback); + PrintToPDF(options, callback); } void NativeWindow::ShowDefinitionForSelection() { diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc index ee47742c687a..0ba9ea662e45 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc @@ -79,7 +79,8 @@ namespace printing { PrintPreviewMessageHandler::PrintPreviewMessageHandler( WebContents* web_contents) - : content::WebContentsObserver(web_contents) { + : request_id_(0), + content::WebContentsObserver(web_contents) { DCHECK(web_contents); } @@ -92,8 +93,6 @@ void PrintPreviewMessageHandler::OnDidGetPreviewPageCount( NOTREACHED(); return; } - - LOG(ERROR) << "OnDidGetPreviewPageCount: " << params.page_count; } void PrintPreviewMessageHandler::OnDidPreviewPage( @@ -101,7 +100,6 @@ void PrintPreviewMessageHandler::OnDidPreviewPage( 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( @@ -122,7 +120,6 @@ void PrintPreviewMessageHandler::OnMetafileReadyForPrinting( if (!data || !data->size()) return; - LOG(ERROR) << params.preview_request_id; atom::NativeWindow* window = atom::NativeWindow::FromWebContents( web_contents()); base::FilePath save_path; @@ -147,39 +144,6 @@ void PrintPreviewMessageHandler::OnPrintPreviewFailed(int document_cookie, RunPrintToPDFCallback(request_id, FAIL_PREVIEW); } -//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; @@ -192,24 +156,14 @@ bool PrintPreviewMessageHandler::OnMessageReceived( 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( +void PrintPreviewMessageHandler::PrintToPDF( const mate::Dictionary& options, const atom::NativeWindow::PrintToPDFCallback& callback) { - static int request_id = 0; - request_id++; // A simulated Chromium print preivew setting. const std::string setting_json_str = "{ \ \"pageRage\":[], \ @@ -244,8 +198,9 @@ void PrintPreviewMessageHandler::HandleGetPreview( scoped_ptr settings( static_cast( base::JSONReader::Read(setting_json_str))); - settings->SetInteger(printing::kPreviewRequestID, request_id); - print_to_pdf_callback_map_[request_id] = callback; + settings->SetInteger(printing::kPreviewRequestID, request_id_); + print_to_pdf_callback_map_[request_id_] = callback; + ++request_id_; // Default Print PDF settings: @@ -267,7 +222,6 @@ void PrintPreviewMessageHandler::HandleGetPreview( settings->SetBoolean(printing::kSettingShouldPrintSelectionOnly, print_selection_only); settings->SetBoolean(printing::kSettingLandscape, is_landscape); - LOG(ERROR) << "Print preview request start"; content::RenderViewHost* rvh = web_contents()->GetRenderViewHost(); rvh->Send(new PrintMsg_PrintPreview(rvh->GetRoutingID(), *settings)); } diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.h b/chromium_src/chrome/browser/printing/print_preview_message_handler.h index f4298fb6b2fc..585eca7e0546 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.h +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.h @@ -49,10 +49,8 @@ class PrintPreviewMessageHandler // 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 mate::Dictionary& options, - const atom::NativeWindow::PrintToPDFCallback& callback); + void PrintToPDF(const mate::Dictionary& options, + const atom::NativeWindow::PrintToPDFCallback& callback); private: typedef std::map PrintToPDFCallbackMap; @@ -60,27 +58,19 @@ class PrintPreviewMessageHandler explicit PrintPreviewMessageHandler(content::WebContents* web_contents); friend class content::WebContentsUserData; - // 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, int request_id); - //void OnPrintPreviewCancelled(int document_cookie); - //void OnInvalidPrinterSettings(int document_cookie); - //void OnSetOptionsFromDocument( - //const PrintHostMsg_SetOptionsFromDocument_Params& params); void RunPrintToPDFCallback(int request_id, PrintPDFResult result); + // PrintToPDF request id counter. + int request_id_; + PrintToPDFCallbackMap print_to_pdf_callback_map_; DISALLOW_COPY_AND_ASSIGN(PrintPreviewMessageHandler); diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper.cc b/chromium_src/chrome/renderer/printing/print_web_view_helper.cc index 550735f709b5..643340deac3b 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper.cc +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper.cc @@ -717,19 +717,16 @@ void PrintWebViewHelper::OnPrintPreview(const base::DictionaryValue& settings) { blink::WebLocalFrame* frame; if (GetPrintFrame(&frame)) { print_preview_context_.InitWithFrame(frame); - LOG(ERROR) << "OnPrintPreview1"; if (!print_preview_context_.source_frame()) { DidFinishPrinting(FAIL_PREVIEW); return; } - LOG(ERROR) << "OnPrintPreview2"; if (!UpdatePrintSettings(print_preview_context_.source_frame(), print_preview_context_.source_node(), settings)) { DidFinishPrinting(FAIL_PREVIEW); return; } - LOG(ERROR) << "OnPrintPreview3"; is_print_ready_metafile_sent_ = false; PrepareFrameForPreviewDocument(); } From c0a6cb69bf21847c84b850fc8a537d0d878bfb65 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Tue, 9 Jun 2015 13:07:40 +0800 Subject: [PATCH 13/28] Move printToPDF API to WebContents. Also expose in webview. --- atom/browser/api/atom_api_web_contents.cc | 18 ++++++++++++++++++ atom/browser/api/atom_api_web_contents.h | 3 +++ atom/browser/api/atom_api_window.cc | 13 ------------- atom/browser/native_window.cc | 6 ------ atom/browser/native_window.h | 4 ---- atom/renderer/lib/web-view/web-view.coffee | 1 + 6 files changed, 22 insertions(+), 23 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index ec24ab45fa24..e325ed902aed 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -18,6 +18,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "brightray/browser/inspectable_web_contents.h" +#include "chrome/browser/printing/print_preview_message_handler.h" #include "content/public/browser/favicon_status.h" #include "content/public/browser/guest_host.h" #include "content/public/browser/navigation_details.h" @@ -137,6 +138,7 @@ WebContents::WebContents(const mate::Dictionary& options) inspectable_web_contents_ = managed_web_contents(); Observe(GetWebContents()); + printing::PrintPreviewMessageHandler::CreateForWebContents(web_contents); } WebContents::~WebContents() { @@ -580,6 +582,7 @@ void WebContents::UnregisterServiceWorker( callback); } +<<<<<<< HEAD void WebContents::SetAudioMuted(bool muted) { web_contents()->SetAudioMuted(muted); } @@ -588,6 +591,20 @@ bool WebContents::IsAudioMuted() { return web_contents()->IsAudioMuted(); } +void WebContents::PrintToPDF(mate::Arguments* args) { + mate::Dictionary options; + base::Callback callback; + if (!(args->Length() == 1 && args->GetNext(&callback)) && + !(args->Length() == 2 && args->GetNext(&options) + && args->GetNext(&callback))) { + args->ThrowError(); + return; + } + + printing::PrintPreviewMessageHandler::FromWebContents(web_contents())-> + PrintToPDF(options, callback); +} + void WebContents::Undo() { web_contents()->Undo(); } @@ -760,6 +777,7 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder( .SetMethod("unregisterServiceWorker", &WebContents::UnregisterServiceWorker) .SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker) + .SetMethod("printToPDF", &WebContents::PrintToPDF) .Build()); return mate::ObjectTemplateBuilder( diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 7c20144517f3..0f8f08889fef 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -90,6 +90,9 @@ class WebContents : public mate::EventEmitter, void SetAudioMuted(bool muted); bool IsAudioMuted(); + // Print current page as PDF. + void PrintToPDF(mate::Arguments* args); + // Editing commands. void Undo(); void Redo(); diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 4b6ab9c95422..69271c0db328 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -430,18 +430,6 @@ void Window::Print(mate::Arguments* args) { window_->Print(settings.silent, settings.print_background); } -void Window::PrintToPDF(mate::Arguments* args) { - mate::Dictionary options; - base::Callback callback; - if (!(args->Length() == 1 && args->GetNext(&callback)) && - !(args->Length() == 2 && args->GetNext(&options) - && args->GetNext(&callback))) { - args->ThrowError(); - return; - } - window_->PrintToPDF(options, callback); -} - void Window::SetProgressBar(double progress) { window_->SetProgressBar(progress); } @@ -554,7 +542,6 @@ void Window::BuildPrototype(v8::Isolate* isolate, .SetMethod("isWebViewFocused", &Window::IsWebViewFocused) .SetMethod("capturePage", &Window::CapturePage) .SetMethod("print", &Window::Print) - .SetMethod("printToPDF", &Window::PrintToPDF) .SetMethod("setProgressBar", &Window::SetProgressBar) .SetMethod("setOverlayIcon", &Window::SetOverlayIcon) .SetMethod("_setMenu", &Window::SetMenu) diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index e1cdab59471b..581565ad188c 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -265,12 +265,6 @@ void NativeWindow::Print(bool silent, bool print_background) { PrintNow(silent, print_background); } -void NativeWindow::PrintToPDF(const mate::Dictionary& options, - const PrintToPDFCallback& callback) { - printing::PrintPreviewMessageHandler::FromWebContents(GetWebContents())-> - PrintToPDF(options, callback); -} - void NativeWindow::ShowDefinitionForSelection() { NOTIMPLEMENTED(); } diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index 78187bc8d458..a5b8b677b2d5 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -158,10 +158,6 @@ class NativeWindow : public CommonWebContentsDelegate, // Print current page. virtual void Print(bool silent, bool print_background); - // Print current page as PDF. - virtual void PrintToPDF(const mate::Dictionary& options, - const PrintToPDFCallback& callback); - // Show popup dictionary. virtual void ShowDefinitionForSelection(); diff --git a/atom/renderer/lib/web-view/web-view.coffee b/atom/renderer/lib/web-view/web-view.coffee index 443b2bca1f2d..3778d7f48d3f 100644 --- a/atom/renderer/lib/web-view/web-view.coffee +++ b/atom/renderer/lib/web-view/web-view.coffee @@ -291,6 +291,7 @@ registerWebViewElement = -> "send" "getId" "inspectServiceWorker" + "printToPDF" ] # Forward proto.foo* method calls to WebViewImpl.foo*. From 6e099af5fee8da4bcfed982f35688191ec975e14 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Wed, 10 Jun 2015 11:34:16 +0800 Subject: [PATCH 14/28] Move PDF printing setting in JS part. --- atom/browser/api/atom_api_web_contents.cc | 17 ++--- atom/browser/api/atom_api_web_contents.h | 5 +- atom/browser/api/lib/web-contents.coffee | 43 ++++++++++++ atom/browser/native_window.h | 1 - .../printing/print_preview_message_handler.cc | 69 ++----------------- .../printing/print_preview_message_handler.h | 12 ++-- 6 files changed, 64 insertions(+), 83 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index e325ed902aed..d72e5539a6de 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -582,6 +582,7 @@ void WebContents::UnregisterServiceWorker( callback); } +<<<<<<< HEAD <<<<<<< HEAD void WebContents::SetAudioMuted(bool muted) { web_contents()->SetAudioMuted(muted); @@ -591,18 +592,10 @@ bool WebContents::IsAudioMuted() { return web_contents()->IsAudioMuted(); } -void WebContents::PrintToPDF(mate::Arguments* args) { - mate::Dictionary options; - base::Callback callback; - if (!(args->Length() == 1 && args->GetNext(&callback)) && - !(args->Length() == 2 && args->GetNext(&options) - && args->GetNext(&callback))) { - args->ThrowError(); - return; - } - +void WebContents::PrintToPDF(const base::DictionaryValue& setting, + const PrintToPDFCallback& callback) { printing::PrintPreviewMessageHandler::FromWebContents(web_contents())-> - PrintToPDF(options, callback); + PrintToPDF(setting, callback); } void WebContents::Undo() { @@ -777,7 +770,7 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder( .SetMethod("unregisterServiceWorker", &WebContents::UnregisterServiceWorker) .SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker) - .SetMethod("printToPDF", &WebContents::PrintToPDF) + .SetMethod("_printToPDF", &WebContents::PrintToPDF) .Build()); return mate::ObjectTemplateBuilder( diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 0f8f08889fef..13abf5184d15 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -52,6 +52,8 @@ class WebContents : public mate::EventEmitter, public content::WebContentsObserver, public content::GpuDataManagerObserver { public: + typedef base::Callback PrintToPDFCallback; + // Create from an existing WebContents. static mate::Handle CreateFrom( v8::Isolate* isolate, brightray::InspectableWebContents* web_contents); @@ -91,7 +93,8 @@ class WebContents : public mate::EventEmitter, bool IsAudioMuted(); // Print current page as PDF. - void PrintToPDF(mate::Arguments* args); + void PrintToPDF(const base::DictionaryValue& setting, + const PrintToPDFCallback& callback); // Editing commands. void Undo(); diff --git a/atom/browser/api/lib/web-contents.coffee b/atom/browser/api/lib/web-contents.coffee index b8c101423d04..5725f0011908 100644 --- a/atom/browser/api/lib/web-contents.coffee +++ b/atom/browser/api/lib/web-contents.coffee @@ -3,6 +3,9 @@ NavigationController = require './navigation-controller' binding = process.atomBinding 'web_contents' ipc = require 'ipc' +nextId = 0 +getNextId = -> ++nextId + wrapWebContents = (webContents) -> # webContents is an EventEmitter. webContents.__proto__ = EventEmitter.prototype @@ -58,6 +61,46 @@ wrapWebContents = (webContents) -> Object.defineProperty event, 'sender', value: webContents ipc.emit channel, event, args... + webContents.printToPDF = (options, callback) -> + printingSetting = + pageRage:[], + mediaSize: + height_microns:297000, + is_default:true, + name:"ISO_A4", + width_microns:210000, + custom_display_name:"A4", + landscape:false, + color:2, + headerFooterEnabled:false, + marginsType:0, + isFirstRequest:false, + requestID: getNextId(), + 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:false, + shouldPrintSelectionOnly:false + + if options.landscape + printingSetting.landscape = options.landscape + if options.marginsType + printingSetting.marginsType = options.marginsType + if options.printSelectionOnly + printingSetting.shouldPrintSelectionOnly = options.printSelectionOnly + if options.printCSSBackgrounds + printingSetting.shouldPrintBackgrounds = options.printBackgrounds + + webContents._printToPDF printingSetting, callback + webContents binding._setWrapWebContents wrapWebContents diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index a5b8b677b2d5..2038775f8d9a 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -55,7 +55,6 @@ class NativeWindow : public CommonWebContentsDelegate, public content::NotificationObserver { public: typedef base::Callback CapturePageCallback; - typedef base::Callback PrintToPDFCallback; class DialogScope { public: diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc index 0ba9ea662e45..dc7052cab1a1 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc @@ -79,8 +79,7 @@ namespace printing { PrintPreviewMessageHandler::PrintPreviewMessageHandler( WebContents* web_contents) - : request_id_(0), - content::WebContentsObserver(web_contents) { + : content::WebContentsObserver(web_contents) { DCHECK(web_contents); } @@ -162,68 +161,14 @@ bool PrintPreviewMessageHandler::OnMessageReceived( } void PrintPreviewMessageHandler::PrintToPDF( - const mate::Dictionary& options, - const atom::NativeWindow::PrintToPDFCallback& callback) { - // 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\":false, \ - \"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\":false, \ - \"shouldPrintSelectionOnly\":false \ - }"; + const base::DictionaryValue& options, + const atom::api::WebContents::PrintToPDFCallback& callback) { + int request_id; + options.GetInteger(printing::kPreviewRequestID, &request_id); + print_to_pdf_callback_map_[request_id] = callback; - scoped_ptr settings( - static_cast( - base::JSONReader::Read(setting_json_str))); - settings->SetInteger(printing::kPreviewRequestID, request_id_); - print_to_pdf_callback_map_[request_id_] = callback; - ++request_id_; - - - // Default Print PDF settings: - int margins_type = 0; // DEFAULT_MARGINS - bool print_background = false; - bool print_selection_only = false; - bool is_landscape = false; - - if (!options.IsEmpty()) { - options.Get(printing::kSettingMarginsType, &margins_type); - options.Get(printing::kSettingShouldPrintBackgrounds, &print_background); - options.Get(printing::kSettingShouldPrintSelectionOnly, - &print_selection_only); - options.Get(printing::kSettingLandscape, &is_landscape); - } - settings->SetInteger(printing::kSettingMarginsType, margins_type); - settings->SetBoolean(printing::kSettingShouldPrintBackgrounds, - print_background); - settings->SetBoolean(printing::kSettingShouldPrintSelectionOnly, - print_selection_only); - settings->SetBoolean(printing::kSettingLandscape, is_landscape); content::RenderViewHost* rvh = web_contents()->GetRenderViewHost(); - rvh->Send(new PrintMsg_PrintPreview(rvh->GetRoutingID(), *settings)); + rvh->Send(new PrintMsg_PrintPreview(rvh->GetRoutingID(), options)); } void PrintPreviewMessageHandler::RunPrintToPDFCallback( diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.h b/chromium_src/chrome/browser/printing/print_preview_message_handler.h index 585eca7e0546..692baba36ee7 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.h +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.h @@ -7,7 +7,7 @@ #include -#include "atom/browser/native_window.h" +#include "atom/browser/api/atom_api_web_contents.h" #include "base/compiler_specific.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_user_data.h" @@ -49,11 +49,12 @@ class PrintPreviewMessageHandler // content::WebContentsObserver implementation. bool OnMessageReceived(const IPC::Message& message) override; - void PrintToPDF(const mate::Dictionary& options, - const atom::NativeWindow::PrintToPDFCallback& callback); + void PrintToPDF(const base::DictionaryValue& options, + const atom::api::WebContents::PrintToPDFCallback& callback); private: - typedef std::map PrintToPDFCallbackMap; + typedef std::map + PrintToPDFCallbackMap; explicit PrintPreviewMessageHandler(content::WebContents* web_contents); friend class content::WebContentsUserData; @@ -68,9 +69,6 @@ class PrintPreviewMessageHandler void RunPrintToPDFCallback(int request_id, PrintPDFResult result); - // PrintToPDF request id counter. - int request_id_; - PrintToPDFCallbackMap print_to_pdf_callback_map_; DISALLOW_COPY_AND_ASSIGN(PrintPreviewMessageHandler); From ab40da3f31b9cbc8baa173c701b6ce61fc5ffe02 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Wed, 10 Jun 2015 13:18:41 +0800 Subject: [PATCH 15/28] Add silent and savePath options. --- atom/browser/api/lib/web-contents.coffee | 1 + .../printing/print_preview_message_handler.cc | 36 ++++++++++++------- .../printing/print_preview_message_handler.h | 12 +++++-- 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/atom/browser/api/lib/web-contents.coffee b/atom/browser/api/lib/web-contents.coffee index 5725f0011908..865154f0cdc4 100644 --- a/atom/browser/api/lib/web-contents.coffee +++ b/atom/browser/api/lib/web-contents.coffee @@ -89,6 +89,7 @@ wrapWebContents = (webContents) -> collate:true, shouldPrintBackgrounds:false, shouldPrintSelectionOnly:false + silent:false if options.landscape printingSetting.landscape = options.landscape diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc index dc7052cab1a1..9b72a9a10445 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc @@ -119,14 +119,21 @@ void PrintPreviewMessageHandler::OnMetafileReadyForPrinting( if (!data || !data->size()) return; - atom::NativeWindow* window = atom::NativeWindow::FromWebContents( - web_contents()); - base::FilePath save_path; - if (!file_dialog::ShowSaveDialog(window, "Save As", - base::FilePath(FILE_PATH_LITERAL("print.pdf")), - file_dialog::Filters(), &save_path)) { // Users cancel dialog. - RunPrintToPDFCallback(params.preview_request_id, FAIL_CANCEL); - return; + int request_id = params.preview_request_id; + std::string file_path = + print_to_pdf_request_details_map_[request_id].save_path; + base::FilePath save_path = + file_path.empty() ? base::FilePath(FILE_PATH_LITERAL("print.pdf")): + base::FilePath::FromUTF8Unsafe(file_path); + if (!print_to_pdf_request_details_map_[request_id].silent) { + atom::NativeWindow* window = atom::NativeWindow::FromWebContents( + web_contents()); + if (!file_dialog::ShowSaveDialog(window, "Save As", + base::FilePath(FILE_PATH_LITERAL("print.pdf")), + file_dialog::Filters(), &save_path)) { // Users cancel dialog. + RunPrintToPDFCallback(request_id, FAIL_CANCEL); + return; + } } BrowserThread::PostTaskAndReplyWithResult( BrowserThread::FILE, @@ -134,7 +141,7 @@ void PrintPreviewMessageHandler::OnMetafileReadyForPrinting( base::Bind(&SavePDF, data, save_path), base::Bind(&PrintPreviewMessageHandler::RunPrintToPDFCallback, base::Unretained(this), - params.preview_request_id)); + request_id)); } void PrintPreviewMessageHandler::OnPrintPreviewFailed(int document_cookie, @@ -165,7 +172,11 @@ void PrintPreviewMessageHandler::PrintToPDF( const atom::api::WebContents::PrintToPDFCallback& callback) { int request_id; options.GetInteger(printing::kPreviewRequestID, &request_id); - print_to_pdf_callback_map_[request_id] = callback; + PrintToPDFRequestDetails details; + options.GetBoolean("silent", &details.silent); + options.GetString("savePath", &details.save_path); + details.callback = callback; + print_to_pdf_request_details_map_[request_id] = details; content::RenderViewHost* rvh = web_contents()->GetRenderViewHost(); rvh->Send(new PrintMsg_PrintPreview(rvh->GetRoutingID(), options)); @@ -173,8 +184,9 @@ void PrintPreviewMessageHandler::PrintToPDF( void PrintPreviewMessageHandler::RunPrintToPDFCallback( int request_id, PrintPDFResult result) { - print_to_pdf_callback_map_[request_id].Run(static_cast(result)); - print_to_pdf_callback_map_.erase(request_id); + print_to_pdf_request_details_map_[request_id].callback.Run( + static_cast(result)); + print_to_pdf_request_details_map_.erase(request_id); } } // namespace printing diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.h b/chromium_src/chrome/browser/printing/print_preview_message_handler.h index 692baba36ee7..656fde4a6083 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.h +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.h @@ -53,8 +53,14 @@ class PrintPreviewMessageHandler const atom::api::WebContents::PrintToPDFCallback& callback); private: - typedef std::map - PrintToPDFCallbackMap; + struct PrintToPDFRequestDetails { + std::string save_path; + bool silent; + atom::api::WebContents::PrintToPDFCallback callback; + }; + + typedef std::map + PrintToPDFRequestDetailsMap; explicit PrintPreviewMessageHandler(content::WebContents* web_contents); friend class content::WebContentsUserData; @@ -69,7 +75,7 @@ class PrintPreviewMessageHandler void RunPrintToPDFCallback(int request_id, PrintPDFResult result); - PrintToPDFCallbackMap print_to_pdf_callback_map_; + PrintToPDFRequestDetailsMap print_to_pdf_request_details_map_; DISALLOW_COPY_AND_ASSIGN(PrintPreviewMessageHandler); }; From ac62871645df7bec445312a5a290fbbc4b390a77 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Wed, 10 Jun 2015 15:16:00 +0800 Subject: [PATCH 16/28] Return node::Buffer as a printToPDF callback result. --- atom/browser/api/atom_api_web_contents.h | 2 +- atom/browser/api/lib/web-contents.coffee | 1 - .../printing/print_preview_message_handler.cc | 71 +++++-------------- .../printing/print_preview_message_handler.h | 22 ++---- 4 files changed, 25 insertions(+), 71 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 13abf5184d15..dbd75db286fd 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -52,7 +52,7 @@ class WebContents : public mate::EventEmitter, public content::WebContentsObserver, public content::GpuDataManagerObserver { public: - typedef base::Callback PrintToPDFCallback; + typedef base::Callback)> PrintToPDFCallback; // Create from an existing WebContents. static mate::Handle CreateFrom( diff --git a/atom/browser/api/lib/web-contents.coffee b/atom/browser/api/lib/web-contents.coffee index 865154f0cdc4..5725f0011908 100644 --- a/atom/browser/api/lib/web-contents.coffee +++ b/atom/browser/api/lib/web-contents.coffee @@ -89,7 +89,6 @@ wrapWebContents = (webContents) -> collate:true, shouldPrintBackgrounds:false, shouldPrintSelectionOnly:false - silent:false if options.landscape printingSetting.landscape = options.landscape diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc index 9b72a9a10445..50739ed57323 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc @@ -25,6 +25,8 @@ #include "printing/print_job_constants.h" #include "printing/pdf_metafile_skia.h" +#include "atom/common/node_includes.h" + using content::BrowserThread; using content::WebContents; @@ -60,18 +62,6 @@ base::RefCountedBytes* GetDataFromHandle(base::SharedMemoryHandle handle, return base::RefCountedBytes::TakeVector(&data); } -printing::PrintPreviewMessageHandler::PrintPDFResult -SavePDF(const scoped_refptr& data, - const base::FilePath& save_path) { - printing::PdfMetafileSkia metafile; - metafile.InitFromData(static_cast(data->front()), data->size()); - base::File file(save_path, - base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); - return metafile.SaveTo(&file)? - printing::PrintPreviewMessageHandler::SUCCESS : - printing::PrintPreviewMessageHandler::FAIL_SAVEFILE; -} - } // namespace namespace printing { @@ -111,43 +101,15 @@ void PrintPreviewMessageHandler::OnMetafileReadyForPrinting( 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 data( + base::RefCountedBytes *data = ( GetDataFromHandle(params.metafile_data_handle, params.data_size)); - if (!data || !data->size()) - return; - - int request_id = params.preview_request_id; - std::string file_path = - print_to_pdf_request_details_map_[request_id].save_path; - base::FilePath save_path = - file_path.empty() ? base::FilePath(FILE_PATH_LITERAL("print.pdf")): - base::FilePath::FromUTF8Unsafe(file_path); - if (!print_to_pdf_request_details_map_[request_id].silent) { - atom::NativeWindow* window = atom::NativeWindow::FromWebContents( - web_contents()); - if (!file_dialog::ShowSaveDialog(window, "Save As", - base::FilePath(FILE_PATH_LITERAL("print.pdf")), - file_dialog::Filters(), &save_path)) { // Users cancel dialog. - RunPrintToPDFCallback(request_id, FAIL_CANCEL); - return; - } - } - BrowserThread::PostTaskAndReplyWithResult( - BrowserThread::FILE, - FROM_HERE, - base::Bind(&SavePDF, data, save_path), - base::Bind(&PrintPreviewMessageHandler::RunPrintToPDFCallback, - base::Unretained(this), - request_id)); + RunPrintToPDFCallback(params.preview_request_id, data); } void PrintPreviewMessageHandler::OnPrintPreviewFailed(int document_cookie, int request_id) { StopWorker(document_cookie); - RunPrintToPDFCallback(request_id, FAIL_PREVIEW); + RunPrintToPDFCallback(request_id, nullptr); } bool PrintPreviewMessageHandler::OnMessageReceived( @@ -172,21 +134,26 @@ void PrintPreviewMessageHandler::PrintToPDF( const atom::api::WebContents::PrintToPDFCallback& callback) { int request_id; options.GetInteger(printing::kPreviewRequestID, &request_id); - PrintToPDFRequestDetails details; - options.GetBoolean("silent", &details.silent); - options.GetString("savePath", &details.save_path); - details.callback = callback; - print_to_pdf_request_details_map_[request_id] = details; + print_to_pdf_callback_map_[request_id] = callback; content::RenderViewHost* rvh = web_contents()->GetRenderViewHost(); rvh->Send(new PrintMsg_PrintPreview(rvh->GetRoutingID(), options)); } void PrintPreviewMessageHandler::RunPrintToPDFCallback( - int request_id, PrintPDFResult result) { - print_to_pdf_request_details_map_[request_id].callback.Run( - static_cast(result)); - print_to_pdf_request_details_map_.erase(request_id); + int request_id, base::RefCountedBytes* data) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::Locker locker(isolate); + v8::HandleScope handle_scope(isolate); + if (data) { + v8::Local buffer = node::Buffer::Use( + const_cast(reinterpret_cast(data->front())), + data->size()); + print_to_pdf_callback_map_[request_id].Run(buffer); + } else { + print_to_pdf_callback_map_[request_id].Run(v8::Null(isolate)); + } + print_to_pdf_callback_map_.erase(request_id); } } // namespace printing diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.h b/chromium_src/chrome/browser/printing/print_preview_message_handler.h index 656fde4a6083..bfdd436b196c 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.h +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.h @@ -37,13 +37,6 @@ class PrintPreviewMessageHandler : public content::WebContentsObserver, public content::WebContentsUserData { public: - enum PrintPDFResult { - SUCCESS, - FAIL_PREVIEW, - FAIL_SAVEFILE, - FAIL_CANCEL, - }; - ~PrintPreviewMessageHandler() override; // content::WebContentsObserver implementation. @@ -53,14 +46,8 @@ class PrintPreviewMessageHandler const atom::api::WebContents::PrintToPDFCallback& callback); private: - struct PrintToPDFRequestDetails { - std::string save_path; - bool silent; - atom::api::WebContents::PrintToPDFCallback callback; - }; - - typedef std::map - PrintToPDFRequestDetailsMap; + typedef std::map + PrintToPDFCallbackMap; explicit PrintPreviewMessageHandler(content::WebContents* web_contents); friend class content::WebContentsUserData; @@ -73,9 +60,10 @@ class PrintPreviewMessageHandler const PrintHostMsg_DidPreviewDocument_Params& params); void OnPrintPreviewFailed(int document_cookie, int request_id); - void RunPrintToPDFCallback(int request_id, PrintPDFResult result); + void RunPrintToPDFCallback( + int request_id, base::RefCountedBytes* data); - PrintToPDFRequestDetailsMap print_to_pdf_request_details_map_; + PrintToPDFCallbackMap print_to_pdf_callback_map_; DISALLOW_COPY_AND_ASSIGN(PrintPreviewMessageHandler); }; From 47439cd77c95a535bdd52f7d602b412f387dff7b Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Wed, 10 Jun 2015 15:43:33 +0800 Subject: [PATCH 17/28] Fix a type error. --- atom/browser/api/lib/web-contents.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/browser/api/lib/web-contents.coffee b/atom/browser/api/lib/web-contents.coffee index 5725f0011908..95b651e13d3d 100644 --- a/atom/browser/api/lib/web-contents.coffee +++ b/atom/browser/api/lib/web-contents.coffee @@ -96,7 +96,7 @@ wrapWebContents = (webContents) -> printingSetting.marginsType = options.marginsType if options.printSelectionOnly printingSetting.shouldPrintSelectionOnly = options.printSelectionOnly - if options.printCSSBackgrounds + if options.printBackgrounds printingSetting.shouldPrintBackgrounds = options.printBackgrounds webContents._printToPDF printingSetting, callback From 93243ef223b0c47422c878772d55196ee97a0229 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Wed, 10 Jun 2015 18:29:07 +0800 Subject: [PATCH 18/28] Remove some unused IPC messages. --- atom/browser/api/atom_api_window.h | 1 - .../printing/print_preview_message_handler.cc | 19 --------- .../printing/print_preview_message_handler.h | 13 ------ chromium_src/chrome/common/print_messages.h | 42 ------------------- .../printing/print_web_view_helper.cc | 41 ------------------ 5 files changed, 116 deletions(-) diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index 828ab2ab9014..43a32e86f45a 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -132,7 +132,6 @@ class Window : public mate::EventEmitter, bool IsDocumentEdited(); void CapturePage(mate::Arguments* args); void Print(mate::Arguments* args); - void PrintToPDF(mate::Arguments* args); void SetProgressBar(double progress); void SetOverlayIcon(const gfx::Image& overlay, const std::string& description); diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc index 50739ed57323..5a6a17034a63 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc @@ -76,21 +76,6 @@ PrintPreviewMessageHandler::PrintPreviewMessageHandler( PrintPreviewMessageHandler::~PrintPreviewMessageHandler() { } -void PrintPreviewMessageHandler::OnDidGetPreviewPageCount( - const PrintHostMsg_DidGetPreviewPageCount_Params& params) { - if (params.page_count <= 0) { - NOTREACHED(); - return; - } -} - -void PrintPreviewMessageHandler::OnDidPreviewPage( - const PrintHostMsg_DidPreviewPage_Params& params) { - int page_number = params.page_number; - if (page_number < FIRST_PAGE_INDEX || !params.data_size) - return; -} - void PrintPreviewMessageHandler::OnMetafileReadyForPrinting( const PrintHostMsg_DidPreviewDocument_Params& params) { // Always try to stop the worker. @@ -116,10 +101,6 @@ 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, diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.h b/chromium_src/chrome/browser/printing/print_preview_message_handler.h index bfdd436b196c..391261d08e0f 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.h +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.h @@ -12,22 +12,12 @@ #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 mate { -class Dictionary; -} - -namespace gfx { -class Rect; -} - namespace printing { struct PageSizeMargins; @@ -53,9 +43,6 @@ class PrintPreviewMessageHandler friend class content::WebContentsUserData; // Message handlers. - 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, int request_id); diff --git a/chromium_src/chrome/common/print_messages.h b/chromium_src/chrome/common/print_messages.h index fc9c1d493509..cd775d0478b7 100644 --- a/chromium_src/chrome/common/print_messages.h +++ b/chromium_src/chrome/common/print_messages.h @@ -187,40 +187,6 @@ IPC_STRUCT_BEGIN(PrintHostMsg_ScriptedPrint_Params) IPC_STRUCT_MEMBER(printing::MarginType, margin_type) IPC_STRUCT_END() -// Parameters to describe a rendered preview page. -IPC_STRUCT_BEGIN(PrintHostMsg_DidPreviewPage_Params) - // A shared memory handle to metafile data for a draft document of the page. - IPC_STRUCT_MEMBER(base::SharedMemoryHandle, metafile_data_handle) - - // Size of metafile data. - IPC_STRUCT_MEMBER(uint32, data_size) - - // |page_number| is zero-based and can be |printing::INVALID_PAGE_INDEX| if it - // is just a check. - IPC_STRUCT_MEMBER(int, page_number) - - // The id of the preview request. - IPC_STRUCT_MEMBER(int, preview_request_id) -IPC_STRUCT_END() - -// Parameters sent along with the page count. -IPC_STRUCT_BEGIN(PrintHostMsg_DidGetPreviewPageCount_Params) - // Cookie for the document to ensure correctness. - IPC_STRUCT_MEMBER(int, document_cookie) - - // Total page count. - IPC_STRUCT_MEMBER(int, page_count) - - // Indicates whether the previewed document is modifiable. - IPC_STRUCT_MEMBER(bool, is_modifiable) - - // The id of the preview request. - IPC_STRUCT_MEMBER(int, preview_request_id) - - // Indicates whether the existing preview data needs to be cleared or not. - IPC_STRUCT_MEMBER(bool, clear_preview_data) -IPC_STRUCT_END() - // Parameters to describe a rendered document. IPC_STRUCT_BEGIN(PrintHostMsg_DidPreviewDocument_Params) // A shared memory handle to metafile data. @@ -318,20 +284,12 @@ IPC_MESSAGE_ROUTED0(PrintHostMsg_ShowInvalidPrinterSettingsError) IPC_MESSAGE_ROUTED1(PrintHostMsg_PrintingFailed, int /* document cookie */) -// Notify the browser a print preview page has been rendered. -IPC_MESSAGE_ROUTED1(PrintHostMsg_DidPreviewPage, - PrintHostMsg_DidPreviewPage_Params /* params */) - // Sends back to the browser the complete rendered document (non-draft mode, // used for printing) that was requested by a PrintMsg_PrintPreview message. // The memory handle in this message is already valid in the browser process. IPC_MESSAGE_ROUTED1(PrintHostMsg_MetafileReadyForPrinting, PrintHostMsg_DidPreviewDocument_Params /* params */) -// Notify the browser the number of pages in the print preview document. -IPC_MESSAGE_ROUTED1(PrintHostMsg_DidGetPreviewPageCount, - PrintHostMsg_DidGetPreviewPageCount_Params /* params */) - IPC_MESSAGE_ROUTED2(PrintHostMsg_PrintPreviewFailed, int /* document cookie */, int /* request_id */); diff --git a/chromium_src/chrome/renderer/printing/print_web_view_helper.cc b/chromium_src/chrome/renderer/printing/print_web_view_helper.cc index 643340deac3b..cba75b651b6b 100644 --- a/chromium_src/chrome/renderer/printing/print_web_view_helper.cc +++ b/chromium_src/chrome/renderer/printing/print_web_view_helper.cc @@ -777,31 +777,6 @@ bool PrintWebViewHelper::CreatePreviewDocument() { return false; } - PageSizeMargins default_page_layout; - ComputePageLayoutInPointsForCss(print_preview_context_.prepared_frame(), 0, - print_params, ignore_css_margins_, NULL, - &default_page_layout); - - //bool has_page_size_style = - //PrintingFrameHasPageSizeStyle(print_preview_context_.prepared_frame(), - //print_preview_context_.total_page_count()); - int dpi = GetDPI(&print_params); - - gfx::Rect printable_area_in_points( - ConvertUnit(print_params.printable_area.x(), dpi, kPointsPerInch), - ConvertUnit(print_params.printable_area.y(), dpi, kPointsPerInch), - ConvertUnit(print_params.printable_area.width(), dpi, kPointsPerInch), - ConvertUnit(print_params.printable_area.height(), dpi, kPointsPerInch)); - - - PrintHostMsg_DidGetPreviewPageCount_Params params; - params.page_count = print_preview_context_.total_page_count(); - params.is_modifiable = print_preview_context_.IsModifiable(); - params.document_cookie = print_params.document_cookie; - params.preview_request_id = print_params.preview_request_id; - params.clear_preview_data = print_preview_context_.generate_draft_pages(); - Send(new PrintHostMsg_DidGetPreviewPageCount(routing_id(), params)); - while (!print_preview_context_.IsFinalPageRendered()) { int page_number = print_preview_context_.GetNextPageNumber(); DCHECK_GE(page_number, 0); @@ -1226,22 +1201,6 @@ bool PrintWebViewHelper::PreviewPageRendered(int page_number, return false; } - PrintHostMsg_DidPreviewPage_Params preview_page_params; - // Get the size of the resulting metafile. - uint32 buf_size = metafile->GetDataSize(); - DCHECK_GT(buf_size, 0u); - if (!CopyMetafileDataToSharedMem( - metafile, &(preview_page_params.metafile_data_handle))) { - LOG(ERROR) << "CopyMetafileDataToSharedMem failed"; - print_preview_context_.set_error(PREVIEW_ERROR_METAFILE_COPY_FAILED); - return false; - } - preview_page_params.data_size = buf_size; - preview_page_params.page_number = page_number; - preview_page_params.preview_request_id = - print_pages_params_->params.preview_request_id; - - Send(new PrintHostMsg_DidPreviewPage(routing_id(), preview_page_params)); return true; } From ccbe554ec004587b1036025139a8780dbc8ae840 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Wed, 10 Jun 2015 20:07:14 +0800 Subject: [PATCH 19/28] Make callback aligns node.js style. --- atom/browser/api/atom_api_web_contents.h | 4 +++- .../browser/printing/print_preview_message_handler.cc | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index dbd75db286fd..891fd0bcb436 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -52,7 +52,9 @@ class WebContents : public mate::EventEmitter, public content::WebContentsObserver, public content::GpuDataManagerObserver { public: - typedef base::Callback)> PrintToPDFCallback; + // For node.js callback function type: function(error, buffer) + typedef base::Callback, v8::Local)> + PrintToPDFCallback; // Create from an existing WebContents. static mate::Handle CreateFrom( diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc index 5a6a17034a63..7005b1c24e9d 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc @@ -130,9 +130,12 @@ void PrintPreviewMessageHandler::RunPrintToPDFCallback( v8::Local buffer = node::Buffer::Use( const_cast(reinterpret_cast(data->front())), data->size()); - print_to_pdf_callback_map_[request_id].Run(buffer); + print_to_pdf_callback_map_[request_id].Run(v8::Null(isolate), buffer); } else { - print_to_pdf_callback_map_[request_id].Run(v8::Null(isolate)); + v8::Local error_message = v8::String::NewFromUtf8(isolate, + "Fail to generate PDF"); + print_to_pdf_callback_map_[request_id].Run( + v8::Exception::Error(error_message), v8::Null(isolate)); } print_to_pdf_callback_map_.erase(request_id); } From 559eb20e7fcad0e0c449179edd23ed54fd04936c Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Thu, 11 Jun 2015 14:43:45 +0800 Subject: [PATCH 20/28] Fixing type: printBackgrounds => printBackground --- atom/browser/api/lib/web-contents.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/browser/api/lib/web-contents.coffee b/atom/browser/api/lib/web-contents.coffee index 95b651e13d3d..8855b6d35f5f 100644 --- a/atom/browser/api/lib/web-contents.coffee +++ b/atom/browser/api/lib/web-contents.coffee @@ -97,7 +97,7 @@ wrapWebContents = (webContents) -> if options.printSelectionOnly printingSetting.shouldPrintSelectionOnly = options.printSelectionOnly if options.printBackgrounds - printingSetting.shouldPrintBackgrounds = options.printBackgrounds + printingSetting.shouldPrintBackgrounds = options.printBackground webContents._printToPDF printingSetting, callback From f22662ffb20c1bed88fc4b0d18f9dcd47e15d200 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Thu, 11 Jun 2015 15:04:58 +0800 Subject: [PATCH 21/28] :memo: Update docs. --- docs/api/browser-window.md | 48 +++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 58e6fa73e35c..fb45ce110371 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -571,32 +571,6 @@ Calling `window.print()` in web page is equivalent to call doesn't need print feature, you can safely remove `pdf.dll` in saving binary size. -### BrowserWindow.printToPDF([options], callback) - -* `options` Object - * `marginsType` Integer - Specify the type of margins to use - * 0 - default - * 1 - none - * 2 - minimum - * `shouldPrintBackgrounds` Boolean - Whether to print CSS backgrounds. - * `shouldPrintSelectionOnly` Boolean - Whether to print selection only. - * `landscape` Boolean - `true` for landscape, `false` for portrait. - -* `callback` Function - `function(statusCode) {}` - * `statusCode` Integer - * 0 - Success. - * 1 - Fail to generate PDF file on renderer part. - * 2 - Fail to save PDF file on local disk. - * 3 - Users cancel the prompted save file dialog. - -Prints windows' web page as PDF with Chromium's preview printing custom -settings. The API will prompt a SaveDialog to allow user custom the file path -for saving the generated PDF file on disk. - -By default, the options will be -`{marginsType:0, shouldPrintBackgrounds:false, shouldPrintSelectionOnly:false, - landscape:false}`. - ### BrowserWindow.loadUrl(url, [options]) Same with `webContents.loadUrl(url, [options])`. @@ -976,6 +950,28 @@ Unregisters any serviceworker if present and returns boolean as response to `callback` when the JS promise is fullfilled or false when the JS promise is rejected. +### WebContents.printToPDF(options, callback) + +* `options` Object + * `marginsType` Integer - Specify the type of margins to use + * 0 - default + * 1 - none + * 2 - minimum + * `printBackground` Boolean - Whether to print CSS backgrounds. + * `printSelectionOnly` Boolean - Whether to print selection only. + * `landscape` Boolean - `true` for landscape, `false` for portrait. + +* `callback` Function - `function(error, data) {}` + * `error` Error + * `data` Buffer - PDF file content + +Prints windows' web page as PDF with Chromium's preview printing custom +settings. + +By default, the options will be +`{marginsType:0, printBackgrounds:false, printSelectionOnly:false, + landscape:false}`. + ### WebContents.send(channel[, args...]) * `channel` String From 894f9c0cb0b62244745707cc9775babb5f2593e8 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Thu, 11 Jun 2015 15:52:48 +0800 Subject: [PATCH 22/28] Don't use duprecated node buffer api, fix build error on OS X. --- .../chrome/browser/printing/print_preview_message_handler.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc index 7005b1c24e9d..78f01c5de016 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc @@ -128,6 +128,7 @@ void PrintPreviewMessageHandler::RunPrintToPDFCallback( v8::HandleScope handle_scope(isolate); if (data) { v8::Local buffer = node::Buffer::Use( + isolate, const_cast(reinterpret_cast(data->front())), data->size()); print_to_pdf_callback_map_[request_id].Run(v8::Null(isolate), buffer); From 93bbc6c8109ce95990fcdfe5a5c73070507b96a0 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Sat, 13 Jun 2015 15:47:32 +0800 Subject: [PATCH 23/28] Simplify the pdf-data handled code. --- .../printing/print_preview_message_handler.cc | 37 +++++++------------ .../printing/print_preview_message_handler.h | 2 +- 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc index 78f01c5de016..3971b9552504 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc @@ -48,20 +48,6 @@ void StopWorker(int document_cookie) { } } -base::RefCountedBytes* GetDataFromHandle(base::SharedMemoryHandle handle, - uint32 data_size) { - scoped_ptr shared_buf( - new base::SharedMemory(handle, true)); - if (!shared_buf->Map(data_size)) { - NOTREACHED(); - return NULL; - } - - unsigned char* data_begin = static_cast(shared_buf->memory()); - std::vector data(data_begin, data_begin + data_size); - return base::RefCountedBytes::TakeVector(&data); -} - } // namespace namespace printing { @@ -86,15 +72,22 @@ void PrintPreviewMessageHandler::OnMetafileReadyForPrinting( return; } - base::RefCountedBytes *data = ( - GetDataFromHandle(params.metafile_data_handle, params.data_size)); - RunPrintToPDFCallback(params.preview_request_id, data); + scoped_ptr shared_buf( + new base::SharedMemory(params.metafile_data_handle, true)); + if (!shared_buf->Map(params.data_size)) { + RunPrintToPDFCallback(params.preview_request_id, nullptr, 0); + return; + } + + RunPrintToPDFCallback(params.preview_request_id, + static_cast(shared_buf->memory()), + params.data_size); } void PrintPreviewMessageHandler::OnPrintPreviewFailed(int document_cookie, int request_id) { StopWorker(document_cookie); - RunPrintToPDFCallback(request_id, nullptr); + RunPrintToPDFCallback(request_id, nullptr, 0); } bool PrintPreviewMessageHandler::OnMessageReceived( @@ -122,15 +115,13 @@ void PrintPreviewMessageHandler::PrintToPDF( } void PrintPreviewMessageHandler::RunPrintToPDFCallback( - int request_id, base::RefCountedBytes* data) { + int request_id, char* data, uint32 data_size) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::Locker locker(isolate); v8::HandleScope handle_scope(isolate); if (data) { - v8::Local buffer = node::Buffer::Use( - isolate, - const_cast(reinterpret_cast(data->front())), - data->size()); + v8::Local buffer = node::Buffer::New(isolate, + data, static_cast(data_size)); print_to_pdf_callback_map_[request_id].Run(v8::Null(isolate), buffer); } else { v8::Local error_message = v8::String::NewFromUtf8(isolate, diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.h b/chromium_src/chrome/browser/printing/print_preview_message_handler.h index 391261d08e0f..a16591dd9f66 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.h +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.h @@ -48,7 +48,7 @@ class PrintPreviewMessageHandler void OnPrintPreviewFailed(int document_cookie, int request_id); void RunPrintToPDFCallback( - int request_id, base::RefCountedBytes* data); + int request_id, char* data, uint32 data_size); PrintToPDFCallbackMap print_to_pdf_callback_map_; From 57580e00f9d05e94889b2a64bcf06b133bfb7656 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Sat, 13 Jun 2015 16:02:16 +0800 Subject: [PATCH 24/28] Fix code style. --- atom/browser/api/atom_api_web_contents.cc | 3 +-- atom/browser/api/atom_api_web_contents.h | 2 +- atom/browser/common_web_contents_delegate.cc | 3 +++ atom/browser/native_window.cc | 3 --- .../browser/printing/print_preview_message_handler.cc | 8 -------- 5 files changed, 5 insertions(+), 14 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index d72e5539a6de..959b0e344dbf 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -138,7 +138,6 @@ WebContents::WebContents(const mate::Dictionary& options) inspectable_web_contents_ = managed_web_contents(); Observe(GetWebContents()); - printing::PrintPreviewMessageHandler::CreateForWebContents(web_contents); } WebContents::~WebContents() { @@ -593,7 +592,7 @@ bool WebContents::IsAudioMuted() { } void WebContents::PrintToPDF(const base::DictionaryValue& setting, - const PrintToPDFCallback& callback) { + const PrintToPDFCallback& callback) { printing::PrintPreviewMessageHandler::FromWebContents(web_contents())-> PrintToPDF(setting, callback); } diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 891fd0bcb436..bab7c9e40643 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -96,7 +96,7 @@ class WebContents : public mate::EventEmitter, // Print current page as PDF. void PrintToPDF(const base::DictionaryValue& setting, - const PrintToPDFCallback& callback); + const PrintToPDFCallback& callback); // Editing commands. void Undo(); diff --git a/atom/browser/common_web_contents_delegate.cc b/atom/browser/common_web_contents_delegate.cc index 087205d37d5b..437d4d725f73 100644 --- a/atom/browser/common_web_contents_delegate.cc +++ b/atom/browser/common_web_contents_delegate.cc @@ -12,6 +12,7 @@ #include "atom/browser/ui/file_dialog.h" #include "atom/browser/web_dialog_helper.h" #include "base/files/file_util.h" +#include "chrome/browser/printing/print_preview_message_handler.h" #include "chrome/browser/ui/browser_dialogs.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/render_process_host.h" @@ -102,6 +103,8 @@ void CommonWebContentsDelegate::InitWithWebContents( owner_window_ = owner_window; web_contents->SetDelegate(this); + printing::PrintPreviewMessageHandler::CreateForWebContents(web_contents); + // Create InspectableWebContents. web_contents_.reset(brightray::InspectableWebContents::Create(web_contents)); web_contents_->SetDelegate(this); diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 581565ad188c..8eb05cb9b0f2 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -28,8 +28,6 @@ #include "brightray/browser/inspectable_web_contents.h" #include "brightray/browser/inspectable_web_contents_view.h" #include "chrome/browser/printing/print_view_manager_basic.h" -#include "chrome/browser/printing/print_preview_message_handler.h" -#include "chrome/browser/ui/browser_dialogs.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/notification_details.h" @@ -99,7 +97,6 @@ NativeWindow::NativeWindow(content::WebContents* web_contents, zoom_factor_(1.0), weak_factory_(this) { printing::PrintViewManagerBasic::CreateForWebContents(web_contents); - printing::PrintPreviewMessageHandler::CreateForWebContents(web_contents); InitWithWebContents(web_contents, this); diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc index 3971b9552504..51bfffce9cb1 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc @@ -4,14 +4,7 @@ #include "chrome/browser/printing/print_preview_message_handler.h" -#include - -#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" @@ -20,7 +13,6 @@ #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" From 47eac062f63a65ddc1c8e46602895d001985711d Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Sat, 13 Jun 2015 21:23:45 +0800 Subject: [PATCH 25/28] Expose Print API to webContents and webView. Also move the print implementation from window to webContents. --- atom/browser/api/atom_api_web_contents.cc | 37 ++++++++++++++++++-- atom/browser/api/atom_api_web_contents.h | 1 + atom/browser/api/atom_api_window.cc | 37 -------------------- atom/browser/api/atom_api_window.h | 1 - atom/browser/api/lib/browser-window.coffee | 1 + atom/browser/common_web_contents_delegate.cc | 2 ++ atom/browser/native_window.cc | 8 ----- atom/browser/native_window.h | 3 -- atom/renderer/lib/web-view/web-view.coffee | 1 + docs/api/browser-window.md | 32 +++++++++-------- docs/api/web-view-tag.md | 4 +++ 11 files changed, 62 insertions(+), 65 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 959b0e344dbf..192955e6acbb 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -18,6 +18,7 @@ #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "brightray/browser/inspectable_web_contents.h" +#include "chrome/browser/printing/print_view_manager_basic.h" #include "chrome/browser/printing/print_preview_message_handler.h" #include "content/public/browser/favicon_status.h" #include "content/public/browser/guest_host.h" @@ -41,6 +42,15 @@ #include "atom/common/node_includes.h" +namespace { + +struct PrintSettings { + bool silent; + bool print_background; +}; + +} // namespace + namespace mate { template<> @@ -65,6 +75,19 @@ struct Converter { } }; +template<> +struct Converter { + static bool FromV8(v8::Isolate* isolate, v8::Local val, + PrintSettings* out) { + mate::Dictionary dict; + if (!ConvertFromV8(isolate, val, &dict)) + return false; + dict.Get("silent", &(out->silent)); + dict.Get("printBackground", &(out->print_background)); + return true; + } +}; + } // namespace mate @@ -581,8 +604,6 @@ void WebContents::UnregisterServiceWorker( callback); } -<<<<<<< HEAD -<<<<<<< HEAD void WebContents::SetAudioMuted(bool muted) { web_contents()->SetAudioMuted(muted); } @@ -591,6 +612,17 @@ bool WebContents::IsAudioMuted() { return web_contents()->IsAudioMuted(); } +void WebContents::Print(mate::Arguments* args) { + PrintSettings settings = { false, false }; + if (args->Length() == 1 && !args->GetNext(&settings)) { + args->ThrowError(); + return; + } + + printing::PrintViewManagerBasic::FromWebContents(web_contents())-> + PrintNow(settings.silent, settings.print_background); +} + void WebContents::PrintToPDF(const base::DictionaryValue& setting, const PrintToPDFCallback& callback) { printing::PrintPreviewMessageHandler::FromWebContents(web_contents())-> @@ -769,6 +801,7 @@ mate::ObjectTemplateBuilder WebContents::GetObjectTemplateBuilder( .SetMethod("unregisterServiceWorker", &WebContents::UnregisterServiceWorker) .SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker) + .SetMethod("print", &WebContents::Print) .SetMethod("_printToPDF", &WebContents::PrintToPDF) .Build()); diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index bab7c9e40643..655087f9b0f5 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -93,6 +93,7 @@ class WebContents : public mate::EventEmitter, void UnregisterServiceWorker(const base::Callback&); void SetAudioMuted(bool muted); bool IsAudioMuted(); + void Print(mate::Arguments* args); // Print current page as PDF. void PrintToPDF(const base::DictionaryValue& setting, diff --git a/atom/browser/api/atom_api_window.cc b/atom/browser/api/atom_api_window.cc index 69271c0db328..0ad9a329e6cc 100644 --- a/atom/browser/api/atom_api_window.cc +++ b/atom/browser/api/atom_api_window.cc @@ -20,32 +20,6 @@ #include "atom/common/node_includes.h" -namespace { - -struct PrintSettings { - bool silent; - bool print_background; -}; - -} // namespace - -namespace mate { - -template<> -struct Converter { - static bool FromV8(v8::Isolate* isolate, v8::Local val, - PrintSettings* out) { - mate::Dictionary dict; - if (!ConvertFromV8(isolate, val, &dict)) - return false; - dict.Get("silent", &(out->silent)); - dict.Get("printBackground", &(out->print_background)); - return true; - } -}; - -} // namespace mate - namespace atom { namespace api { @@ -420,16 +394,6 @@ void Window::CapturePage(mate::Arguments* args) { rect, base::Bind(&OnCapturePageDone, args->isolate(), callback)); } -void Window::Print(mate::Arguments* args) { - PrintSettings settings = { false, false }; - if (args->Length() == 1 && !args->GetNext(&settings)) { - args->ThrowError(); - return; - } - - window_->Print(settings.silent, settings.print_background); -} - void Window::SetProgressBar(double progress) { window_->SetProgressBar(progress); } @@ -541,7 +505,6 @@ void Window::BuildPrototype(v8::Isolate* isolate, .SetMethod("blurWebView", &Window::BlurWebView) .SetMethod("isWebViewFocused", &Window::IsWebViewFocused) .SetMethod("capturePage", &Window::CapturePage) - .SetMethod("print", &Window::Print) .SetMethod("setProgressBar", &Window::SetProgressBar) .SetMethod("setOverlayIcon", &Window::SetOverlayIcon) .SetMethod("_setMenu", &Window::SetMenu) diff --git a/atom/browser/api/atom_api_window.h b/atom/browser/api/atom_api_window.h index 43a32e86f45a..d2b9d28034df 100644 --- a/atom/browser/api/atom_api_window.h +++ b/atom/browser/api/atom_api_window.h @@ -131,7 +131,6 @@ class Window : public mate::EventEmitter, void SetDocumentEdited(bool edited); bool IsDocumentEdited(); void CapturePage(mate::Arguments* args); - void Print(mate::Arguments* args); void SetProgressBar(double progress); void SetOverlayIcon(const gfx::Image& overlay, const std::string& description); diff --git a/atom/browser/api/lib/browser-window.coffee b/atom/browser/api/lib/browser-window.coffee index f0691b19b8fa..b0ffe6b37ef9 100644 --- a/atom/browser/api/lib/browser-window.coffee +++ b/atom/browser/api/lib/browser-window.coffee @@ -83,5 +83,6 @@ BrowserWindow::isDevToolsOpened = -> @webContents.isDevToolsOpened() BrowserWindow::toggleDevTools = -> @webContents.toggleDevTools() BrowserWindow::inspectElement = -> @webContents.inspectElement.apply @webContents, arguments BrowserWindow::inspectServiceWorker = -> @webContents.inspectServiceWorker() +BrowserWindow::print = -> @webContents.print.apply @webContents, arguments module.exports = BrowserWindow diff --git a/atom/browser/common_web_contents_delegate.cc b/atom/browser/common_web_contents_delegate.cc index 437d4d725f73..285b93014e44 100644 --- a/atom/browser/common_web_contents_delegate.cc +++ b/atom/browser/common_web_contents_delegate.cc @@ -13,6 +13,7 @@ #include "atom/browser/web_dialog_helper.h" #include "base/files/file_util.h" #include "chrome/browser/printing/print_preview_message_handler.h" +#include "chrome/browser/printing/print_view_manager_basic.h" #include "chrome/browser/ui/browser_dialogs.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/render_process_host.h" @@ -103,6 +104,7 @@ void CommonWebContentsDelegate::InitWithWebContents( owner_window_ = owner_window; web_contents->SetDelegate(this); + printing::PrintViewManagerBasic::CreateForWebContents(web_contents); printing::PrintPreviewMessageHandler::CreateForWebContents(web_contents); // Create InspectableWebContents. diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 8eb05cb9b0f2..48ea9e76c32c 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -27,7 +27,6 @@ #include "base/strings/utf_string_conversions.h" #include "brightray/browser/inspectable_web_contents.h" #include "brightray/browser/inspectable_web_contents_view.h" -#include "chrome/browser/printing/print_view_manager_basic.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/notification_details.h" @@ -96,8 +95,6 @@ NativeWindow::NativeWindow(content::WebContents* web_contents, has_dialog_attached_(false), zoom_factor_(1.0), weak_factory_(this) { - printing::PrintViewManagerBasic::CreateForWebContents(web_contents); - InitWithWebContents(web_contents, this); options.Get(switches::kFrame, &has_frame_); @@ -257,11 +254,6 @@ bool NativeWindow::IsDocumentEdited() { void NativeWindow::SetMenu(ui::MenuModel* menu) { } -void NativeWindow::Print(bool silent, bool print_background) { - printing::PrintViewManagerBasic::FromWebContents(GetWebContents())-> - PrintNow(silent, print_background); -} - void NativeWindow::ShowDefinitionForSelection() { NOTIMPLEMENTED(); } diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index 2038775f8d9a..0298101ce043 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -154,9 +154,6 @@ class NativeWindow : public CommonWebContentsDelegate, virtual void CapturePage(const gfx::Rect& rect, const CapturePageCallback& callback); - // Print current page. - virtual void Print(bool silent, bool print_background); - // Show popup dictionary. virtual void ShowDefinitionForSelection(); diff --git a/atom/renderer/lib/web-view/web-view.coffee b/atom/renderer/lib/web-view/web-view.coffee index 3778d7f48d3f..72fee948d137 100644 --- a/atom/renderer/lib/web-view/web-view.coffee +++ b/atom/renderer/lib/web-view/web-view.coffee @@ -291,6 +291,7 @@ registerWebViewElement = -> "send" "getId" "inspectServiceWorker" + "print" "printToPDF" ] diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index fb45ce110371..a25c4d88527d 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -556,20 +556,7 @@ process. ### BrowserWindow.print([options]) -* `options` Object - * `silent` Boolean - Don't ask user for print settings, defaults to `false` - * `printBackground` Boolean - Also prints the background color and image of - the web page, defaults to `false`. - -Prints window's web page. When `silent` is set to `false`, Electron will pick -up system's default printer and default settings for printing. - -Calling `window.print()` in web page is equivalent to call -`BrowserWindow.print({silent: false, printBackground: false})`. - -**Note:** On Windows, the print API relies on `pdf.dll`. If your application -doesn't need print feature, you can safely remove `pdf.dll` in saving binary -size. +Same with `webContents.print([options])` ### BrowserWindow.loadUrl(url, [options]) @@ -950,6 +937,23 @@ Unregisters any serviceworker if present and returns boolean as response to `callback` when the JS promise is fullfilled or false when the JS promise is rejected. +### WebContents.print([options]) + +* `options` Object + * `silent` Boolean - Don't ask user for print settings, defaults to `false` + * `printBackground` Boolean - Also prints the background color and image of + the web page, defaults to `false`. + +Prints window's web page. When `silent` is set to `false`, Electron will pick +up system's default printer and default settings for printing. + +Calling `window.print()` in web page is equivalent to call +`WebContents.print({silent: false, printBackground: false})`. + +**Note:** On Windows, the print API relies on `pdf.dll`. If your application +doesn't need print feature, you can safely remove `pdf.dll` in saving binary +size. + ### WebContents.printToPDF(options, callback) * `options` Object diff --git a/docs/api/web-view-tag.md b/docs/api/web-view-tag.md index 4a227d769cb7..2a9344048253 100644 --- a/docs/api/web-view-tag.md +++ b/docs/api/web-view-tag.md @@ -308,6 +308,10 @@ Executes editing command `replace` in page. Executes editing command `replaceMisspelling` in page. +### `.print([options])` + +Prints webview's web page. Same with `webContents.print([options])`. + ### ``.send(channel[, args...]) * `channel` String From 1eba552a8d1ab4479824275f0e0a2cea9337bd8c Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Sat, 13 Jun 2015 21:39:06 +0800 Subject: [PATCH 26/28] Also Expose printToPDF to BrowserWindow. --- atom/browser/api/lib/browser-window.coffee | 1 + docs/api/browser-window.md | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/atom/browser/api/lib/browser-window.coffee b/atom/browser/api/lib/browser-window.coffee index b0ffe6b37ef9..818d737a894f 100644 --- a/atom/browser/api/lib/browser-window.coffee +++ b/atom/browser/api/lib/browser-window.coffee @@ -84,5 +84,6 @@ BrowserWindow::toggleDevTools = -> @webContents.toggleDevTools() BrowserWindow::inspectElement = -> @webContents.inspectElement.apply @webContents, arguments BrowserWindow::inspectServiceWorker = -> @webContents.inspectServiceWorker() BrowserWindow::print = -> @webContents.print.apply @webContents, arguments +BrowserWindow::printToPDF = -> @webContents.printToPDF.apply @webContents, arguments module.exports = BrowserWindow diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index a25c4d88527d..05cddc7978a7 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -558,6 +558,10 @@ process. Same with `webContents.print([options])` +### BrowserWindow.printToPDF(options, callback) + +Same with `webContents.printToPDF(options, callback)` + ### BrowserWindow.loadUrl(url, [options]) Same with `webContents.loadUrl(url, [options])`. From 16348fc8956dcee0712863bc9bb2b866532740ea Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Tue, 16 Jun 2015 19:42:17 +0800 Subject: [PATCH 27/28] Copy pdf data on IO thread to avoid causing main process hangs. --- .../printing/print_preview_message_handler.cc | 39 ++++++++++++------- .../printing/print_preview_message_handler.h | 3 +- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc index 51bfffce9cb1..ca70ac2c58ef 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.cc +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.cc @@ -40,6 +40,19 @@ void StopWorker(int document_cookie) { } } +char* CopyPDFDataOnIOThread( + const PrintHostMsg_DidPreviewDocument_Params& params) { + DCHECK_CURRENTLY_ON(BrowserThread::IO); + scoped_ptr shared_buf( + new base::SharedMemory(params.metafile_data_handle, true)); + if (!shared_buf->Map(params.data_size)) + return nullptr; + char* memory_pdf_data = static_cast(shared_buf->memory()); + char* pdf_data = new char[params.data_size]; + memcpy(pdf_data, memory_pdf_data, params.data_size); + return pdf_data; +} + } // namespace namespace printing { @@ -64,22 +77,20 @@ void PrintPreviewMessageHandler::OnMetafileReadyForPrinting( return; } - scoped_ptr shared_buf( - new base::SharedMemory(params.metafile_data_handle, true)); - if (!shared_buf->Map(params.data_size)) { - RunPrintToPDFCallback(params.preview_request_id, nullptr, 0); - return; - } - - RunPrintToPDFCallback(params.preview_request_id, - static_cast(shared_buf->memory()), - params.data_size); + BrowserThread::PostTaskAndReplyWithResult( + BrowserThread::IO, + FROM_HERE, + base::Bind(&CopyPDFDataOnIOThread, params), + base::Bind(&PrintPreviewMessageHandler::RunPrintToPDFCallback, + base::Unretained(this), + params.preview_request_id, + params.data_size)); } void PrintPreviewMessageHandler::OnPrintPreviewFailed(int document_cookie, int request_id) { StopWorker(document_cookie); - RunPrintToPDFCallback(request_id, nullptr, 0); + RunPrintToPDFCallback(request_id, 0, nullptr); } bool PrintPreviewMessageHandler::OnMessageReceived( @@ -107,12 +118,14 @@ void PrintPreviewMessageHandler::PrintToPDF( } void PrintPreviewMessageHandler::RunPrintToPDFCallback( - int request_id, char* data, uint32 data_size) { + int request_id, uint32 data_size, char* data) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::Locker locker(isolate); v8::HandleScope handle_scope(isolate); if (data) { - v8::Local buffer = node::Buffer::New(isolate, + v8::Local buffer = node::Buffer::Use(isolate, data, static_cast(data_size)); print_to_pdf_callback_map_[request_id].Run(v8::Null(isolate), buffer); } else { diff --git a/chromium_src/chrome/browser/printing/print_preview_message_handler.h b/chromium_src/chrome/browser/printing/print_preview_message_handler.h index a16591dd9f66..453d78761bbe 100644 --- a/chromium_src/chrome/browser/printing/print_preview_message_handler.h +++ b/chromium_src/chrome/browser/printing/print_preview_message_handler.h @@ -47,8 +47,7 @@ class PrintPreviewMessageHandler const PrintHostMsg_DidPreviewDocument_Params& params); void OnPrintPreviewFailed(int document_cookie, int request_id); - void RunPrintToPDFCallback( - int request_id, char* data, uint32 data_size); + void RunPrintToPDFCallback(int request_id, uint32 data_size, char* data); PrintToPDFCallbackMap print_to_pdf_callback_map_; From 82b1607c1e8400913b0342f8a32669e94bdab295 Mon Sep 17 00:00:00 2001 From: Haojian Wu Date: Tue, 16 Jun 2015 20:17:58 +0800 Subject: [PATCH 28/28] :memo: Add missing printToPDF API in webview. --- docs/api/web-view-tag.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/api/web-view-tag.md b/docs/api/web-view-tag.md index 2a9344048253..54e82ef3a7bc 100644 --- a/docs/api/web-view-tag.md +++ b/docs/api/web-view-tag.md @@ -312,6 +312,10 @@ Executes editing command `replaceMisspelling` in page. Prints webview's web page. Same with `webContents.print([options])`. +### `.printToPDF(options, callback)` + +Prints webview's web page as PDF, Same with `webContents.printToPDF(options, callback)` + ### ``.send(channel[, args...]) * `channel` String