From 85f83680d7000ff80f3754918697eb8c8e2f38d1 Mon Sep 17 00:00:00 2001 From: Alexei Bykov Date: Tue, 24 Mar 2015 18:40:08 +0300 Subject: [PATCH] Add PDF printing support (issue #1478). --- cef_paths.gypi | 4 + include/capi/cef_browser_capi.h | 32 +++ include/capi/cef_print_handler_capi.h | 7 + include/cef_browser.h | 28 +++ include/cef_print_handler.h | 9 + include/internal/cef_types.h | 86 +++++++ include/internal/cef_types_wrappers.h | 42 +++- libcef/browser/browser_host_impl.cc | 21 ++ libcef/browser/browser_host_impl.h | 3 + libcef/browser/browser_main.cc | 2 + libcef/browser/printing/print_dialog_linux.cc | 35 ++- libcef/browser/printing/print_dialog_linux.h | 4 + libcef/browser/printing/print_view_manager.cc | 229 +++++++++++++++++- libcef/browser/printing/print_view_manager.h | 24 ++ .../printing/print_view_manager_base.cc | 4 - .../printing/print_view_manager_base.h | 6 +- .../printing/printing_message_filter.cc | 7 + .../printing/printing_message_filter.h | 4 + libcef/resources/cef_resources.grd | 1 - libcef/resources/print_preview_page_stub.html | 1 - libcef_dll/cpptoc/browser_host_cpptoc.cc | 32 +++ .../cpptoc/pdf_print_callback_cpptoc.cc | 61 +++++ libcef_dll/cpptoc/pdf_print_callback_cpptoc.h | 37 +++ libcef_dll/cpptoc/print_handler_cpptoc.cc | 17 ++ libcef_dll/ctocpp/browser_host_ctocpp.cc | 23 ++ libcef_dll/ctocpp/browser_host_ctocpp.h | 2 + .../ctocpp/pdf_print_callback_ctocpp.cc | 57 +++++ libcef_dll/ctocpp/pdf_print_callback_ctocpp.h | 40 +++ libcef_dll/ctocpp/print_handler_ctocpp.cc | 15 ++ libcef_dll/ctocpp/print_handler_ctocpp.h | 1 + libcef_dll/libcef_dll.cc | 2 + libcef_dll/wrapper/libcef_dll_wrapper.cc | 2 + libcef_dll/wrapper_types.h | 1 + patch/patch.cfg | 6 + patch/patches/print_header_footer_1478.patch | 125 ++++++++++ tests/cefclient/browser/print_handler_gtk.cc | 11 + tests/cefclient/browser/print_handler_gtk.h | 1 + tests/cefclient/browser/resource.h | 3 +- tests/cefclient/browser/root_window_gtk.cc | 1 + tests/cefclient/browser/test_runner.cc | 75 +++++- tests/cefclient/cefclient_mac.mm | 1 + tests/cefclient/resources/win/cefclient.rc | 1 + 42 files changed, 1039 insertions(+), 24 deletions(-) delete mode 100644 libcef/resources/print_preview_page_stub.html create mode 100644 libcef_dll/cpptoc/pdf_print_callback_cpptoc.cc create mode 100644 libcef_dll/cpptoc/pdf_print_callback_cpptoc.h create mode 100644 libcef_dll/ctocpp/pdf_print_callback_ctocpp.cc create mode 100644 libcef_dll/ctocpp/pdf_print_callback_ctocpp.h create mode 100644 patch/patches/print_header_footer_1478.patch diff --git a/cef_paths.gypi b/cef_paths.gypi index 75f5222f9..948ebc1a5 100644 --- a/cef_paths.gypi +++ b/cef_paths.gypi @@ -216,6 +216,8 @@ 'libcef_dll/cpptoc/navigation_entry_cpptoc.h', 'libcef_dll/ctocpp/navigation_entry_visitor_ctocpp.cc', 'libcef_dll/ctocpp/navigation_entry_visitor_ctocpp.h', + 'libcef_dll/ctocpp/pdf_print_callback_ctocpp.cc', + 'libcef_dll/ctocpp/pdf_print_callback_ctocpp.h', 'libcef_dll/cpptoc/post_data_cpptoc.cc', 'libcef_dll/cpptoc/post_data_cpptoc.h', 'libcef_dll/cpptoc/post_data_element_cpptoc.cc', @@ -408,6 +410,8 @@ 'libcef_dll/ctocpp/navigation_entry_ctocpp.h', 'libcef_dll/cpptoc/navigation_entry_visitor_cpptoc.cc', 'libcef_dll/cpptoc/navigation_entry_visitor_cpptoc.h', + 'libcef_dll/cpptoc/pdf_print_callback_cpptoc.cc', + 'libcef_dll/cpptoc/pdf_print_callback_cpptoc.h', 'libcef_dll/ctocpp/post_data_ctocpp.cc', 'libcef_dll/ctocpp/post_data_ctocpp.h', 'libcef_dll/ctocpp/post_data_element_ctocpp.cc', diff --git a/include/capi/cef_browser_capi.h b/include/capi/cef_browser_capi.h index 418411fa4..5307498da 100644 --- a/include/capi/cef_browser_capi.h +++ b/include/capi/cef_browser_capi.h @@ -230,6 +230,27 @@ typedef struct _cef_navigation_entry_visitor_t { } cef_navigation_entry_visitor_t; +/// +// Callback structure for cef_browser_host_t::PrintToPDF. The functions of this +// structure will be called on the browser process UI thread. +/// +typedef struct _cef_pdf_print_callback_t { + /// + // Base structure. + /// + cef_base_t base; + + /// + // Method that will be executed when the PDF printing has completed. |path| is + // the output path. |ok| will be true (1) if the printing completed + // successfully or false (0) otherwise. + /// + void (CEF_CALLBACK *on_pdf_print_finished)( + struct _cef_pdf_print_callback_t* self, const cef_string_t* path, + int ok); +} cef_pdf_print_callback_t; + + /// // Structure used to represent the browser process aspects of a browser window. // The functions of this structure can only be called in the browser process. @@ -346,6 +367,17 @@ typedef struct _cef_browser_host_t { /// void (CEF_CALLBACK *print)(struct _cef_browser_host_t* self); + /// + // Print the current browser contents to the PDF file specified by |path| and + // execute |callback| on completion. The caller is responsible for deleting + // |path| when done. For PDF printing to work on Linux you must implement the + // cef_print_handler_t::GetPdfPaperSize function. + /// + void (CEF_CALLBACK *print_to_pdf)(struct _cef_browser_host_t* self, + const cef_string_t* path, + const struct _cef_pdf_print_settings_t* settings, + struct _cef_pdf_print_callback_t* callback); + /// // Search for |searchText|. |identifier| can be used to have multiple searches // running simultaniously. |forward| indicates whether to search forward or diff --git a/include/capi/cef_print_handler_capi.h b/include/capi/cef_print_handler_capi.h index f2e29ae51..fbcb71281 100644 --- a/include/capi/cef_print_handler_capi.h +++ b/include/capi/cef_print_handler_capi.h @@ -124,6 +124,13 @@ typedef struct _cef_print_handler_t { // Reset client state related to printing. /// void (CEF_CALLBACK *on_print_reset)(struct _cef_print_handler_t* self); + + /// + // Return the PDF paper size in device units. Used in combination with + // cef_browser_host_t::print_to_pdf(). + /// + cef_size_t (CEF_CALLBACK *get_pdf_paper_size)( + struct _cef_print_handler_t* self, int device_units_per_inch); } cef_print_handler_t; diff --git a/include/cef_browser.h b/include/cef_browser.h index 2b8d9481e..b27709e6a 100644 --- a/include/cef_browser.h +++ b/include/cef_browser.h @@ -234,6 +234,23 @@ class CefNavigationEntryVisitor : public virtual CefBase { }; +/// +// Callback interface for CefBrowserHost::PrintToPDF. The methods of this class +// will be called on the browser process UI thread. +/// +/*--cef(source=client)--*/ +class CefPdfPrintCallback : public virtual CefBase { + public: + /// + // Method that will be executed when the PDF printing has completed. |path| + // is the output path. |ok| will be true if the printing completed + // successfully or false otherwise. + /// + /*--cef()--*/ + virtual void OnPdfPrintFinished(const CefString& path, bool ok) =0; +}; + + /// // Class used to represent the browser process aspects of a browser window. The // methods of this class can only be called in the browser process. They may be @@ -389,6 +406,17 @@ class CefBrowserHost : public virtual CefBase { /*--cef()--*/ virtual void Print() =0; + /// + // Print the current browser contents to the PDF file specified by |path| and + // execute |callback| on completion. The caller is responsible for deleting + // |path| when done. For PDF printing to work on Linux you must implement the + // CefPrintHandler::GetPdfPaperSize method. + /// + /*--cef(optional_param=callback)--*/ + virtual void PrintToPDF(const CefString& path, + const CefPdfPrintSettings& settings, + CefRefPtr callback) =0; + /// // Search for |searchText|. |identifier| can be used to have multiple searches // running simultaniously. |forward| indicates whether to search forward or diff --git a/include/cef_print_handler.h b/include/cef_print_handler.h index a157cbbd6..57ae3781d 100644 --- a/include/cef_print_handler.h +++ b/include/cef_print_handler.h @@ -115,6 +115,15 @@ class CefPrintHandler : public virtual CefBase { /// /*--cef()--*/ virtual void OnPrintReset() =0; + + /// + // Return the PDF paper size in device units. Used in combination with + // CefBrowserHost::PrintToPDF(). + /// + /*--cef()--*/ + virtual CefSize GetPdfPaperSize(int device_units_per_inch) { + return CefSize(); + } }; #endif // CEF_INCLUDE_CEF_PRINT_HANDLER_H_ diff --git a/include/internal/cef_types.h b/include/internal/cef_types.h index 2a229240d..b378596fd 100644 --- a/include/internal/cef_types.h +++ b/include/internal/cef_types.h @@ -2194,6 +2194,92 @@ typedef enum { JSON_WRITER_PRETTY_PRINT = 1 << 2, } cef_json_writer_options_t; +/// +// Margin type for PDF printing. +/// +typedef enum { + /// + // Default margins. + /// + PDF_PRINT_MARGIN_DEFAULT, + + /// + // No margins. + /// + PDF_PRINT_MARGIN_NONE, + + /// + // Minimum margins. + /// + PDF_PRINT_MARGIN_MINIMUM, + + /// + // Custom margins using the |margin_*| values from cef_pdf_print_settings_t. + /// + PDF_PRINT_MARGIN_CUSTOM, +} cef_pdf_print_margin_type_t; + +/// +// Structure representing PDF print settings. +/// +typedef struct _cef_pdf_print_settings_t { + /// + // Page title to display in the header. Only used if |header_footer_enabled| + // is set to true (1). + /// + cef_string_t header_footer_title; + + /// + // URL to display in the footer. Only used if |header_footer_enabled| is set + // to true (1). + /// + cef_string_t header_footer_url; + + /// + // Output page size in microns. If either of these values is less than or + // equal to zero then the default paper size (A4) will be used. + /// + int page_width; + int page_height; + + /// + // Margins in millimeters. Only used if |margin_type| is set to + // PDF_PRINT_MARGIN_CUSTOM. + /// + double margin_top; + double margin_right; + double margin_bottom; + double margin_left; + + /// + // Margin type. + /// + cef_pdf_print_margin_type_t margin_type; + + /// + // Set to true (1) to print headers and footers or false (0) to not print + // headers and footers. + /// + int header_footer_enabled; + + /// + // Set to true (1) to print the selection only or false (0) to print all. + /// + int selection_only; + + /// + // Set to true (1) for landscape mode or false (0) for portrait mode. + /// + int landscape; + + /// + // Set to true (1) to print background graphics or false (0) to not print + // background graphics. + /// + int backgrounds_enabled; + +} cef_pdf_print_settings_t; + #ifdef __cplusplus } #endif diff --git a/include/internal/cef_types_wrappers.h b/include/internal/cef_types_wrappers.h index ce09fd5cf..b68e9a025 100644 --- a/include/internal/cef_types_wrappers.h +++ b/include/internal/cef_types_wrappers.h @@ -822,7 +822,7 @@ class CefPageRange : public CefStructBase { CefPageRange(const cef_page_range_t& r) // NOLINT(runtime/explicit) : parent(r) {} CefPageRange(const CefPageRange& r) // NOLINT(runtime/explicit) - : parent(r) {} + : parent(r) {} CefPageRange(int from, int to) : parent() { Set(from, to); } @@ -862,4 +862,44 @@ struct CefCursorInfoTraits { /// typedef CefStructBase CefCursorInfo; + +struct CefPdfPrintSettingsTraits { + typedef cef_pdf_print_settings_t struct_type; + + static inline void init(struct_type* s) {} + + static inline void clear(struct_type* s) { + cef_string_clear(&s->header_footer_title); + cef_string_clear(&s->header_footer_url); + } + + static inline void set(const struct_type* src, struct_type* target, + bool copy) { + + cef_string_set(src->header_footer_title.str, + src->header_footer_title.length, &target->header_footer_title, copy); + cef_string_set(src->header_footer_url.str, src->header_footer_url.length, + &target->header_footer_url, copy); + + target->page_width = src->page_width; + target->page_height = src->page_height; + + target->margin_top = src->margin_top; + target->margin_right = src->margin_right; + target->margin_bottom = src->margin_bottom; + target->margin_left = src->margin_left; + target->margin_type = src->margin_type; + + target->header_footer_enabled = src->header_footer_enabled; + target->selection_only = src->selection_only; + target->landscape = src->landscape; + target->backgrounds_enabled = src->backgrounds_enabled; + } +}; + +/// +// Class representing PDF print settings +/// +typedef CefStructBase CefPdfPrintSettings; + #endif // CEF_INCLUDE_INTERNAL_CEF_TYPES_WRAPPERS_H_ diff --git a/libcef/browser/browser_host_impl.cc b/libcef/browser/browser_host_impl.cc index 3dfeae012..e308eb50d 100644 --- a/libcef/browser/browser_host_impl.cc +++ b/libcef/browser/browser_host_impl.cc @@ -832,6 +832,27 @@ void CefBrowserHostImpl::Print() { } } +void CefBrowserHostImpl::PrintToPDF(const CefString& path, + const CefPdfPrintSettings& settings, + CefRefPtr callback) { + if (CEF_CURRENTLY_ON_UIT()) { + if (!web_contents_) + return; + + printing::PrintViewManager::PdfPrintCallback pdf_callback; + if (callback.get()) { + pdf_callback = base::Bind(&CefPdfPrintCallback::OnPdfPrintFinished, + callback.get(), path); + } + printing::PrintViewManager::FromWebContents(web_contents_.get())-> + PrintToPDF(base::FilePath(path), settings, pdf_callback); + } else { + CEF_POST_TASK(CEF_UIT, + base::Bind(&CefBrowserHostImpl::PrintToPDF, this, path, settings, + callback)); + } +} + void CefBrowserHostImpl::Find(int identifier, const CefString& searchText, bool forward, bool matchCase, bool findNext) { if (CEF_CURRENTLY_ON_UIT()) { diff --git a/libcef/browser/browser_host_impl.h b/libcef/browser/browser_host_impl.h index cc920d4d9..f39059d8a 100644 --- a/libcef/browser/browser_host_impl.h +++ b/libcef/browser/browser_host_impl.h @@ -162,6 +162,9 @@ class CefBrowserHostImpl : public CefBrowserHost, CefRefPtr callback) override; void StartDownload(const CefString& url) override; void Print() override; + void PrintToPDF(const CefString& path, + const CefPdfPrintSettings& settings, + CefRefPtr callback) override; void Find(int identifier, const CefString& searchText, bool forward, bool matchCase, bool findNext) override; void StopFinding(bool clearSelection) override; diff --git a/libcef/browser/browser_main.cc b/libcef/browser/browser_main.cc index 13aaac094..9015c861a 100644 --- a/libcef/browser/browser_main.cc +++ b/libcef/browser/browser_main.cc @@ -93,6 +93,8 @@ void CefBrowserMainParts::PostMainMessageLoopStart() { #if defined(OS_LINUX) printing::PrintingContextLinux::SetCreatePrintDialogFunction( &CefPrintDialogLinux::CreatePrintDialog); + printing::PrintingContextLinux::SetPdfPaperSizeFunction( + &CefPrintDialogLinux::GetPdfPaperSize); #endif } diff --git a/libcef/browser/printing/print_dialog_linux.cc b/libcef/browser/printing/print_dialog_linux.cc index 53a5c51e4..899b113c5 100644 --- a/libcef/browser/printing/print_dialog_linux.cc +++ b/libcef/browser/printing/print_dialog_linux.cc @@ -106,6 +106,35 @@ printing::PrintDialogGtkInterface* CefPrintDialogLinux::CreatePrintDialog( return new CefPrintDialogLinux(context); } +// static +gfx::Size CefPrintDialogLinux::GetPdfPaperSize( + printing::PrintingContextLinux* context) { + CEF_REQUIRE_UIT(); + + gfx::Size size; + + CefRefPtr app = CefContentClient::Get()->application(); + if (app.get()) { + CefRefPtr browser_handler = + app->GetBrowserProcessHandler(); + if (browser_handler.get()) { + CefRefPtr handler = browser_handler->GetPrintHandler(); + if (handler.get()) { + const printing::PrintSettings& settings = context->settings(); + CefSize cef_size = handler->GetPdfPaperSize( + settings.device_units_per_inch()); + size.SetSize(cef_size.width, cef_size.height); + } + } + } + + if (size.IsEmpty()) { + LOG(ERROR) << "Empty size value returned in GetPdfPaperSize; " + "PDF printing will fail."; + } + return size; +} + CefPrintDialogLinux::CefPrintDialogLinux(PrintingContextLinux* context) : context_(context) { } @@ -192,10 +221,10 @@ void CefPrintDialogLinux::ReleaseDialog() { } void CefPrintDialogLinux::SetHandler() { - if (handler_.get()) - return; + if (handler_.get()) + return; - CefRefPtr app = CefContentClient::Get()->application(); + CefRefPtr app = CefContentClient::Get()->application(); if (app.get()) { CefRefPtr browser_handler = app->GetBrowserProcessHandler(); diff --git a/libcef/browser/printing/print_dialog_linux.h b/libcef/browser/printing/print_dialog_linux.h index c7fcea771..f6c33aa6c 100644 --- a/libcef/browser/printing/print_dialog_linux.h +++ b/libcef/browser/printing/print_dialog_linux.h @@ -33,6 +33,10 @@ class CefPrintDialogLinux static printing::PrintDialogGtkInterface* CreatePrintDialog( PrintingContextLinux* context); + // Returns the paper size in device units. + static gfx::Size GetPdfPaperSize( + printing::PrintingContextLinux* context); + // printing::CefPrintDialogLinuxInterface implementation. void UseDefaultSettings() override; bool UpdateSettings(printing::PrintSettings* settings) override; diff --git a/libcef/browser/printing/print_view_manager.cc b/libcef/browser/printing/print_view_manager.cc index dd0e4fd8b..1d6004f91 100644 --- a/libcef/browser/printing/print_view_manager.cc +++ b/libcef/browser/printing/print_view_manager.cc @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "include/internal/cef_types_wrappers.h" #include "libcef/browser/printing/print_view_manager.h" #include @@ -12,9 +13,11 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/printing/print_job_manager.h" #include "chrome/browser/printing/print_preview_dialog_controller.h" +#include "chrome/browser/printing/printer_query.h" #include "components/printing/common/print_messages.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/web_contents.h" +#include "printing/pdf_metafile_skia.h" using content::BrowserThread; @@ -22,11 +25,140 @@ DEFINE_WEB_CONTENTS_USER_DATA_KEY(printing::PrintViewManager); namespace printing { +namespace { + +const int PREVIEW_UIID = 12345678; + +// Convert CefPdfPrintSettings into base::DictionaryValue. +void FillInDictionaryFromPdfPrintSettings( + const CefPdfPrintSettings& pdf_settings, + int request_id, + base::DictionaryValue& print_settings) { + // Fixed settings. + print_settings.SetBoolean(kSettingPrintToPDF, true); + print_settings.SetBoolean(kSettingCloudPrintDialog, false); + print_settings.SetBoolean(kSettingPrintWithPrivet, false); + print_settings.SetBoolean(kSettingPrintWithExtension, false); + print_settings.SetInteger(kSettingColor, GRAY); + print_settings.SetInteger(kSettingDuplexMode, SIMPLEX); + print_settings.SetInteger(kSettingCopies, 1); + print_settings.SetBoolean(kSettingCollate, false); + print_settings.SetString(kSettingDeviceName, ""); + print_settings.SetBoolean(kSettingGenerateDraftData, false); + print_settings.SetBoolean(kSettingPreviewModifiable, false); + + // User defined settings. + print_settings.SetBoolean(kSettingLandscape, !!pdf_settings.landscape); + print_settings.SetBoolean(kSettingShouldPrintSelectionOnly, + !!pdf_settings.selection_only); + print_settings.SetBoolean(kSettingShouldPrintBackgrounds, + !!pdf_settings.backgrounds_enabled); + print_settings.SetBoolean(kSettingHeaderFooterEnabled, + !!pdf_settings.header_footer_enabled); + + if (pdf_settings.header_footer_enabled) { + print_settings.SetString(kSettingHeaderFooterTitle, + CefString(&pdf_settings.header_footer_title).ToString16()); + print_settings.SetString(kSettingHeaderFooterURL, + CefString(&pdf_settings.header_footer_url).ToString16()); + } + + if (pdf_settings.page_width > 0 && pdf_settings.page_height > 0) { + scoped_ptr dict(new base::DictionaryValue); + dict->SetInteger(kSettingMediaSizeWidthMicrons, pdf_settings.page_width); + dict->SetInteger(kSettingMediaSizeHeightMicrons, pdf_settings.page_height); + print_settings.Set(kSettingMediaSize, dict.Pass()); + } + + int margin_type = DEFAULT_MARGINS; + switch (pdf_settings.margin_type) { + case PDF_PRINT_MARGIN_NONE: + margin_type = NO_MARGINS; + break; + case PDF_PRINT_MARGIN_MINIMUM: + margin_type = PRINTABLE_AREA_MARGINS; + break; + case PDF_PRINT_MARGIN_CUSTOM: + margin_type = CUSTOM_MARGINS; + break; + default: + break; + } + + print_settings.SetInteger(kSettingMarginsType, margin_type); + if (margin_type == CUSTOM_MARGINS) { + scoped_ptr dict(new base::DictionaryValue); + dict->SetDouble(kSettingMarginTop, pdf_settings.margin_top); + dict->SetDouble(kSettingMarginRight, pdf_settings.margin_right); + dict->SetDouble(kSettingMarginBottom, pdf_settings.margin_bottom); + dict->SetDouble(kSettingMarginLeft, pdf_settings.margin_left); + print_settings.Set(kSettingMarginsCustom, dict.Pass()); + } + + // Service settings. + print_settings.SetInteger(kPreviewUIID, PREVIEW_UIID); + print_settings.SetInteger(kPreviewRequestID, request_id); + print_settings.SetBoolean(kIsFirstRequest, request_id != 0); +} + +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(&PrinterQuery::StopWorker, + printer_query)); + } +} + +scoped_refptr +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 = static_cast(shared_buf->memory()); + std::vector dataVector(data, data + data_size); + return base::RefCountedBytes::TakeVector(&dataVector); +} + +// Write the PDF file to disk. +void SavePdfFile(scoped_refptr data, + const base::FilePath& path, + const PrintViewManager::PdfPrintCallback& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::FILE); + DCHECK_GT(data->size(), 0U); + + PdfMetafileSkia metafile; + metafile.InitFromData(static_cast(data->front()), data->size()); + + base::File file(path, + base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE); + bool ok = file.IsValid() && metafile.SaveTo(&file); + + if (!callback.is_null()) { + BrowserThread::PostTask(BrowserThread::UI, + FROM_HERE, + base::Bind(callback, ok)); + } +} + +} // namespace + PrintViewManager::PrintViewManager(content::WebContents* web_contents) : PrintViewManagerBase(web_contents) { } PrintViewManager::~PrintViewManager() { + TerminatePdfPrintJob(); } #if defined(ENABLE_BASIC_PRINTING) @@ -35,21 +167,104 @@ bool PrintViewManager::PrintForSystemDialogNow() { } #endif // ENABLE_BASIC_PRINTING -void PrintViewManager::RenderProcessGone(base::TerminationStatus status) { - PrintViewManagerBase::RenderProcessGone(status); -} - -void PrintViewManager::OnDidShowPrintDialog() { -} - bool PrintViewManager::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(PrintViewManager, message) IPC_MESSAGE_HANDLER(PrintHostMsg_DidShowPrintDialog, OnDidShowPrintDialog) + IPC_MESSAGE_HANDLER(PrintHostMsg_RequestPrintPreview, + OnRequestPrintPreview) + IPC_MESSAGE_HANDLER(PrintHostMsg_MetafileReadyForPrinting, + OnMetafileReadyForPrinting) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled ? true : PrintViewManagerBase::OnMessageReceived(message); } +void PrintViewManager::NavigationStopped() { + PrintViewManagerBase::NavigationStopped(); + TerminatePdfPrintJob(); +} + +void PrintViewManager::RenderProcessGone(base::TerminationStatus status) { + PrintViewManagerBase::RenderProcessGone(status); + TerminatePdfPrintJob(); +} + +void PrintViewManager::PrintToPDF(const base::FilePath& path, + const CefPdfPrintSettings& settings, + const PdfPrintCallback& callback) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (!web_contents() || pdf_print_settings_) + return; + + pdf_output_path_ = path; + pdf_print_callback_ = callback; + + pdf_print_settings_.reset(new base::DictionaryValue); + FillInDictionaryFromPdfPrintSettings(settings, + ++next_pdf_request_id_, + *pdf_print_settings_); + + Send(new PrintMsg_InitiatePrintPreview(routing_id(), + !!settings.selection_only)); +} + +void PrintViewManager::OnDidShowPrintDialog() { +} + +void PrintViewManager::OnRequestPrintPreview( + const PrintHostMsg_RequestPrintPreview_Params&) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (!web_contents() || !pdf_print_settings_) + return; + + Send(new PrintMsg_PrintPreview(routing_id(), *pdf_print_settings_)); +} + +void PrintViewManager::OnMetafileReadyForPrinting( + const PrintHostMsg_DidPreviewDocument_Params& params) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + StopWorker(params.document_cookie); + + scoped_refptr data_bytes = + GetDataFromHandle(params.metafile_data_handle, params.data_size); + if (!data_bytes || !data_bytes->size()) { + TerminatePdfPrintJob(); + return; + } + + base::FilePath pdf_output_path = pdf_output_path_; + PdfPrintCallback pdf_print_callback = pdf_print_callback_; + + // Reset state information. + pdf_output_path_.clear(); + pdf_print_callback_.Reset(); + pdf_print_settings_.reset(); + + // Save the PDF file to disk and then execute the callback. + BrowserThread::PostTask(BrowserThread::FILE, + FROM_HERE, + base::Bind(&SavePdfFile, data_bytes, pdf_output_path, + pdf_print_callback)); +} + +void PrintViewManager::TerminatePdfPrintJob() { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (!pdf_print_settings_.get()) + return; + + if (!pdf_print_callback_.is_null()) { + // Execute the callback. + BrowserThread::PostTask(BrowserThread::UI, + FROM_HERE, + base::Bind(pdf_print_callback_, false)); + } + + // Reset state information. + pdf_output_path_.clear(); + pdf_print_callback_.Reset(); + pdf_print_settings_.reset(); +} + } // namespace printing diff --git a/libcef/browser/printing/print_view_manager.h b/libcef/browser/printing/print_view_manager.h index d886809e4..30bbeafa0 100644 --- a/libcef/browser/printing/print_view_manager.h +++ b/libcef/browser/printing/print_view_manager.h @@ -8,6 +8,9 @@ #include "libcef/browser/printing/print_view_manager_base.h" #include "content/public/browser/web_contents_user_data.h" +struct PrintHostMsg_DidPreviewDocument_Params; +struct PrintHostMsg_RequestPrintPreview_Params; + namespace content { class RenderProcessHost; } @@ -30,15 +33,36 @@ class PrintViewManager : public PrintViewManagerBase, bool OnMessageReceived(const IPC::Message& message) override; // content::WebContentsObserver implementation. + // Cancels the print job. + void NavigationStopped() override; // Terminates or cancels the print job if one was pending. void RenderProcessGone(base::TerminationStatus status) override; + // Callback executed on PDF printing completion. + typedef base::Callback PdfPrintCallback; + + // Print the current document to a PDF file. Execute |callback| on completion. + void PrintToPDF(const base::FilePath& path, + const CefPdfPrintSettings& settings, + const PdfPrintCallback& callback); + private: explicit PrintViewManager(content::WebContents* web_contents); friend class content::WebContentsUserData; // IPC Message handlers. void OnDidShowPrintDialog(); + void OnRequestPrintPreview(const PrintHostMsg_RequestPrintPreview_Params&); + void OnMetafileReadyForPrinting( + const PrintHostMsg_DidPreviewDocument_Params&); + + void TerminatePdfPrintJob(); + + // Used for printing to PDF. Only accessed on the browser process UI thread. + int next_pdf_request_id_ = -1; + base::FilePath pdf_output_path_; + scoped_ptr pdf_print_settings_; + PdfPrintCallback pdf_print_callback_; DISALLOW_COPY_AND_ASSIGN(PrintViewManager); }; diff --git a/libcef/browser/printing/print_view_manager_base.cc b/libcef/browser/printing/print_view_manager_base.cc index 6d2f0293e..5bd680027 100644 --- a/libcef/browser/printing/print_view_manager_base.cc +++ b/libcef/browser/printing/print_view_manager_base.cc @@ -34,10 +34,6 @@ using content::BrowserThread; namespace printing { -namespace { - -} // namespace - PrintViewManagerBase::PrintViewManagerBase(content::WebContents* web_contents) : content::WebContentsObserver(web_contents), number_pages_(0), diff --git a/libcef/browser/printing/print_view_manager_base.h b/libcef/browser/printing/print_view_manager_base.h index 8cd9f567b..8ee805bac 100644 --- a/libcef/browser/printing/print_view_manager_base.h +++ b/libcef/browser/printing/print_view_manager_base.h @@ -54,6 +54,9 @@ class PrintViewManagerBase : public content::NotificationObserver, // Helper method for Print*Now(). bool PrintNowInternal(IPC::Message* message); + // Cancels the print job. + void NavigationStopped() override; + // Terminates or cancels the print job if one was pending. void RenderProcessGone(base::TerminationStatus status) override; @@ -72,9 +75,6 @@ class PrintViewManagerBase : public content::NotificationObserver, // content::WebContentsObserver implementation. void DidStartLoading() override; - // Cancels the print job. - void NavigationStopped() override; - // IPC Message handlers. void OnDidGetPrintedPagesCount(int cookie, int number_pages); void OnDidGetDocumentCookie(int cookie); diff --git a/libcef/browser/printing/printing_message_filter.cc b/libcef/browser/printing/printing_message_filter.cc index 771a69fe2..3d8cf75eb 100644 --- a/libcef/browser/printing/printing_message_filter.cc +++ b/libcef/browser/printing/printing_message_filter.cc @@ -126,6 +126,7 @@ bool PrintingMessageFilter::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_ScriptedPrint, OnScriptedPrint) IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_UpdatePrintSettings, OnUpdatePrintSettings) + IPC_MESSAGE_HANDLER(PrintHostMsg_CheckForCancel, OnCheckForCancel) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -420,4 +421,10 @@ void PrintingMessageFilter::OnUpdatePrintSettingsReply( } } +void PrintingMessageFilter::OnCheckForCancel(int32 preview_ui_id, + int preview_request_id, + bool* cancel) { + *cancel = false; +} + } // namespace printing diff --git a/libcef/browser/printing/printing_message_filter.h b/libcef/browser/printing/printing_message_filter.h index f169b2368..1a841d365 100644 --- a/libcef/browser/printing/printing_message_filter.h +++ b/libcef/browser/printing/printing_message_filter.h @@ -105,6 +105,10 @@ class PrintingMessageFilter : public content::BrowserMessageFilter { void OnUpdatePrintSettingsReply(scoped_refptr printer_query, IPC::Message* reply_msg); + void OnCheckForCancel(int32 preview_ui_id, + int preview_request_id, + bool* cancel); + const int render_process_id_; scoped_refptr queue_; diff --git a/libcef/resources/cef_resources.grd b/libcef/resources/cef_resources.grd index 63dc921f6..f01db5a7e 100644 --- a/libcef/resources/cef_resources.grd +++ b/libcef/resources/cef_resources.grd @@ -14,7 +14,6 @@ - diff --git a/libcef/resources/print_preview_page_stub.html b/libcef/resources/print_preview_page_stub.html deleted file mode 100644 index 18ecdcb79..000000000 --- a/libcef/resources/print_preview_page_stub.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/libcef_dll/cpptoc/browser_host_cpptoc.cc b/libcef_dll/cpptoc/browser_host_cpptoc.cc index f74927e09..70f832c0f 100644 --- a/libcef_dll/cpptoc/browser_host_cpptoc.cc +++ b/libcef_dll/cpptoc/browser_host_cpptoc.cc @@ -16,6 +16,7 @@ #include "libcef_dll/cpptoc/request_context_cpptoc.h" #include "libcef_dll/ctocpp/client_ctocpp.h" #include "libcef_dll/ctocpp/navigation_entry_visitor_ctocpp.h" +#include "libcef_dll/ctocpp/pdf_print_callback_ctocpp.h" #include "libcef_dll/ctocpp/run_file_dialog_callback_ctocpp.h" #include "libcef_dll/transfer_util.h" @@ -307,6 +308,36 @@ void CEF_CALLBACK browser_host_print(struct _cef_browser_host_t* self) { CefBrowserHostCppToC::Get(self)->Print(); } +void CEF_CALLBACK browser_host_print_to_pdf(struct _cef_browser_host_t* self, + const cef_string_t* path, const struct _cef_pdf_print_settings_t* settings, + cef_pdf_print_callback_t* callback) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: path; type: string_byref_const + DCHECK(path); + if (!path) + return; + // Verify param: settings; type: struct_byref_const + DCHECK(settings); + if (!settings) + return; + // Unverified params: callback + + // Translate param: settings; type: struct_byref_const + CefPdfPrintSettings settingsObj; + if (settings) + settingsObj.Set(*settings, false); + + // Execute + CefBrowserHostCppToC::Get(self)->PrintToPDF( + CefString(path), + settingsObj, + CefPdfPrintCallbackCToCpp::Wrap(callback)); +} + void CEF_CALLBACK browser_host_find(struct _cef_browser_host_t* self, int identifier, const cef_string_t* searchText, int forward, int matchCase, int findNext) { @@ -881,6 +912,7 @@ CefBrowserHostCppToC::CefBrowserHostCppToC() { GetStruct()->run_file_dialog = browser_host_run_file_dialog; GetStruct()->start_download = browser_host_start_download; GetStruct()->print = browser_host_print; + GetStruct()->print_to_pdf = browser_host_print_to_pdf; GetStruct()->find = browser_host_find; GetStruct()->stop_finding = browser_host_stop_finding; GetStruct()->show_dev_tools = browser_host_show_dev_tools; diff --git a/libcef_dll/cpptoc/pdf_print_callback_cpptoc.cc b/libcef_dll/cpptoc/pdf_print_callback_cpptoc.cc new file mode 100644 index 000000000..717b6129f --- /dev/null +++ b/libcef_dll/cpptoc/pdf_print_callback_cpptoc.cc @@ -0,0 +1,61 @@ +// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#include "libcef_dll/cpptoc/pdf_print_callback_cpptoc.h" + + +namespace { + +// MEMBER FUNCTIONS - Body may be edited by hand. + +void CEF_CALLBACK pdf_print_callback_on_pdf_print_finished( + struct _cef_pdf_print_callback_t* self, const cef_string_t* path, int ok) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return; + // Verify param: path; type: string_byref_const + DCHECK(path); + if (!path) + return; + + // Execute + CefPdfPrintCallbackCppToC::Get(self)->OnPdfPrintFinished( + CefString(path), + ok?true:false); +} + +} // namespace + + +// CONSTRUCTOR - Do not edit by hand. + +CefPdfPrintCallbackCppToC::CefPdfPrintCallbackCppToC() { + GetStruct()->on_pdf_print_finished = pdf_print_callback_on_pdf_print_finished; +} + +template<> CefRefPtr CefCppToC::UnwrapDerived( + CefWrapperType type, cef_pdf_print_callback_t* s) { + NOTREACHED() << "Unexpected class type: " << type; + return NULL; +} + +#ifndef NDEBUG +template<> base::AtomicRefCount CefCppToC::DebugObjCt = 0; +#endif + +template<> CefWrapperType CefCppToC::kWrapperType = + WT_PDF_PRINT_CALLBACK; diff --git a/libcef_dll/cpptoc/pdf_print_callback_cpptoc.h b/libcef_dll/cpptoc/pdf_print_callback_cpptoc.h new file mode 100644 index 000000000..db091d304 --- /dev/null +++ b/libcef_dll/cpptoc/pdf_print_callback_cpptoc.h @@ -0,0 +1,37 @@ +// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#ifndef CEF_LIBCEF_DLL_CPPTOC_PDF_PRINT_CALLBACK_CPPTOC_H_ +#define CEF_LIBCEF_DLL_CPPTOC_PDF_PRINT_CALLBACK_CPPTOC_H_ +#pragma once + +#ifndef USING_CEF_SHARED +#pragma message("Warning: "__FILE__" may be accessed wrapper-side only") +#else // USING_CEF_SHARED + +#include "include/cef_browser.h" +#include "include/capi/cef_browser_capi.h" +#include "include/cef_client.h" +#include "include/capi/cef_client_capi.h" +#include "libcef_dll/cpptoc/cpptoc.h" + +// Wrap a C++ class with a C structure. +// This class may be instantiated and accessed wrapper-side only. +class CefPdfPrintCallbackCppToC + : public CefCppToC { + public: + CefPdfPrintCallbackCppToC(); +}; + +#endif // USING_CEF_SHARED +#endif // CEF_LIBCEF_DLL_CPPTOC_PDF_PRINT_CALLBACK_CPPTOC_H_ diff --git a/libcef_dll/cpptoc/print_handler_cpptoc.cc b/libcef_dll/cpptoc/print_handler_cpptoc.cc index c0939ed7e..edeba8ceb 100644 --- a/libcef_dll/cpptoc/print_handler_cpptoc.cc +++ b/libcef_dll/cpptoc/print_handler_cpptoc.cc @@ -104,6 +104,22 @@ void CEF_CALLBACK print_handler_on_print_reset( CefPrintHandlerCppToC::Get(self)->OnPrintReset(); } +cef_size_t CEF_CALLBACK print_handler_get_pdf_paper_size( + struct _cef_print_handler_t* self, int device_units_per_inch) { + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + DCHECK(self); + if (!self) + return CefSize(); + + // Execute + cef_size_t _retval = CefPrintHandlerCppToC::Get(self)->GetPdfPaperSize( + device_units_per_inch); + + // Return type: simple + return _retval; +} + } // namespace @@ -114,6 +130,7 @@ CefPrintHandlerCppToC::CefPrintHandlerCppToC() { GetStruct()->on_print_dialog = print_handler_on_print_dialog; GetStruct()->on_print_job = print_handler_on_print_job; GetStruct()->on_print_reset = print_handler_on_print_reset; + GetStruct()->get_pdf_paper_size = print_handler_get_pdf_paper_size; } template<> CefRefPtr CefCppToCprint(_struct); } +void CefBrowserHostCToCpp::PrintToPDF(const CefString& path, + const CefPdfPrintSettings& settings, + CefRefPtr callback) { + cef_browser_host_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, print_to_pdf)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: path; type: string_byref_const + DCHECK(!path.empty()); + if (path.empty()) + return; + // Unverified params: callback + + // Execute + _struct->print_to_pdf(_struct, + path.GetStruct(), + &settings, + CefPdfPrintCallbackCppToC::Wrap(callback)); +} + void CefBrowserHostCToCpp::Find(int identifier, const CefString& searchText, bool forward, bool matchCase, bool findNext) { cef_browser_host_t* _struct = GetStruct(); diff --git a/libcef_dll/ctocpp/browser_host_ctocpp.h b/libcef_dll/ctocpp/browser_host_ctocpp.h index 51ec31d88..6cdff7e19 100644 --- a/libcef_dll/ctocpp/browser_host_ctocpp.h +++ b/libcef_dll/ctocpp/browser_host_ctocpp.h @@ -50,6 +50,8 @@ class CefBrowserHostCToCpp CefRefPtr callback) OVERRIDE; void StartDownload(const CefString& url) OVERRIDE; void Print() OVERRIDE; + void PrintToPDF(const CefString& path, const CefPdfPrintSettings& settings, + CefRefPtr callback) OVERRIDE; void Find(int identifier, const CefString& searchText, bool forward, bool matchCase, bool findNext) OVERRIDE; void StopFinding(bool clearSelection) OVERRIDE; diff --git a/libcef_dll/ctocpp/pdf_print_callback_ctocpp.cc b/libcef_dll/ctocpp/pdf_print_callback_ctocpp.cc new file mode 100644 index 000000000..cf8d853ea --- /dev/null +++ b/libcef_dll/ctocpp/pdf_print_callback_ctocpp.cc @@ -0,0 +1,57 @@ +// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#include "libcef_dll/ctocpp/pdf_print_callback_ctocpp.h" + + +// VIRTUAL METHODS - Body may be edited by hand. + +void CefPdfPrintCallbackCToCpp::OnPdfPrintFinished(const CefString& path, + bool ok) { + cef_pdf_print_callback_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, on_pdf_print_finished)) + return; + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Verify param: path; type: string_byref_const + DCHECK(!path.empty()); + if (path.empty()) + return; + + // Execute + _struct->on_pdf_print_finished(_struct, + path.GetStruct(), + ok); +} + + +// CONSTRUCTOR - Do not edit by hand. + +CefPdfPrintCallbackCToCpp::CefPdfPrintCallbackCToCpp() { +} + +template<> cef_pdf_print_callback_t* CefCToCpp::UnwrapDerived( + CefWrapperType type, CefPdfPrintCallback* c) { + NOTREACHED() << "Unexpected class type: " << type; + return NULL; +} + +#ifndef NDEBUG +template<> base::AtomicRefCount CefCToCpp::DebugObjCt = 0; +#endif + +template<> CefWrapperType CefCToCpp::kWrapperType = + WT_PDF_PRINT_CALLBACK; diff --git a/libcef_dll/ctocpp/pdf_print_callback_ctocpp.h b/libcef_dll/ctocpp/pdf_print_callback_ctocpp.h new file mode 100644 index 000000000..76bbd6b56 --- /dev/null +++ b/libcef_dll/ctocpp/pdf_print_callback_ctocpp.h @@ -0,0 +1,40 @@ +// Copyright (c) 2015 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. +// +// --------------------------------------------------------------------------- +// +// This file was generated by the CEF translator tool. If making changes by +// hand only do so within the body of existing method and function +// implementations. See the translator.README.txt file in the tools directory +// for more information. +// + +#ifndef CEF_LIBCEF_DLL_CTOCPP_PDF_PRINT_CALLBACK_CTOCPP_H_ +#define CEF_LIBCEF_DLL_CTOCPP_PDF_PRINT_CALLBACK_CTOCPP_H_ +#pragma once + +#ifndef BUILDING_CEF_SHARED +#pragma message("Warning: "__FILE__" may be accessed DLL-side only") +#else // BUILDING_CEF_SHARED + +#include "include/cef_browser.h" +#include "include/capi/cef_browser_capi.h" +#include "include/cef_client.h" +#include "include/capi/cef_client_capi.h" +#include "libcef_dll/ctocpp/ctocpp.h" + +// Wrap a C structure with a C++ class. +// This class may be instantiated and accessed DLL-side only. +class CefPdfPrintCallbackCToCpp + : public CefCToCpp { + public: + CefPdfPrintCallbackCToCpp(); + + // CefPdfPrintCallback methods. + void OnPdfPrintFinished(const CefString& path, bool ok) override; +}; + +#endif // BUILDING_CEF_SHARED +#endif // CEF_LIBCEF_DLL_CTOCPP_PDF_PRINT_CALLBACK_CTOCPP_H_ diff --git a/libcef_dll/ctocpp/print_handler_ctocpp.cc b/libcef_dll/ctocpp/print_handler_ctocpp.cc index 0032e596d..457d690e8 100644 --- a/libcef_dll/ctocpp/print_handler_ctocpp.cc +++ b/libcef_dll/ctocpp/print_handler_ctocpp.cc @@ -101,6 +101,21 @@ void CefPrintHandlerCToCpp::OnPrintReset() { _struct->on_print_reset(_struct); } +CefSize CefPrintHandlerCToCpp::GetPdfPaperSize(int device_units_per_inch) { + cef_print_handler_t* _struct = GetStruct(); + if (CEF_MEMBER_MISSING(_struct, get_pdf_paper_size)) + return CefSize(); + + // AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING + + // Execute + cef_size_t _retval = _struct->get_pdf_paper_size(_struct, + device_units_per_inch); + + // Return type: simple + return _retval; +} + // CONSTRUCTOR - Do not edit by hand. diff --git a/libcef_dll/ctocpp/print_handler_ctocpp.h b/libcef_dll/ctocpp/print_handler_ctocpp.h index da0d23b57..bac7c2340 100644 --- a/libcef_dll/ctocpp/print_handler_ctocpp.h +++ b/libcef_dll/ctocpp/print_handler_ctocpp.h @@ -39,6 +39,7 @@ class CefPrintHandlerCToCpp const CefString& pdf_file_path, CefRefPtr callback) override; void OnPrintReset() override; + CefSize GetPdfPaperSize(int device_units_per_inch) override; }; #endif // BUILDING_CEF_SHARED diff --git a/libcef_dll/libcef_dll.cc b/libcef_dll/libcef_dll.cc index c0eab67b2..f06ed8e12 100644 --- a/libcef_dll/libcef_dll.cc +++ b/libcef_dll/libcef_dll.cc @@ -95,6 +95,7 @@ #include "libcef_dll/ctocpp/life_span_handler_ctocpp.h" #include "libcef_dll/ctocpp/load_handler_ctocpp.h" #include "libcef_dll/ctocpp/navigation_entry_visitor_ctocpp.h" +#include "libcef_dll/ctocpp/pdf_print_callback_ctocpp.h" #include "libcef_dll/ctocpp/print_handler_ctocpp.h" #include "libcef_dll/ctocpp/read_handler_ctocpp.h" #include "libcef_dll/ctocpp/render_handler_ctocpp.h" @@ -232,6 +233,7 @@ CEF_EXPORT void cef_shutdown() { DCHECK(base::AtomicRefCountIsZero(&CefNavigationEntryCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero( &CefNavigationEntryVisitorCToCpp::DebugObjCt)); + DCHECK(base::AtomicRefCountIsZero(&CefPdfPrintCallbackCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefPrintDialogCallbackCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefPrintHandlerCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefPrintJobCallbackCppToC::DebugObjCt)); diff --git a/libcef_dll/wrapper/libcef_dll_wrapper.cc b/libcef_dll/wrapper/libcef_dll_wrapper.cc index 3d7006d53..ed43e9ead 100644 --- a/libcef_dll/wrapper/libcef_dll_wrapper.cc +++ b/libcef_dll/wrapper/libcef_dll_wrapper.cc @@ -54,6 +54,7 @@ #include "libcef_dll/cpptoc/life_span_handler_cpptoc.h" #include "libcef_dll/cpptoc/load_handler_cpptoc.h" #include "libcef_dll/cpptoc/navigation_entry_visitor_cpptoc.h" +#include "libcef_dll/cpptoc/pdf_print_callback_cpptoc.h" #include "libcef_dll/cpptoc/print_handler_cpptoc.h" #include "libcef_dll/cpptoc/read_handler_cpptoc.h" #include "libcef_dll/cpptoc/render_handler_cpptoc.h" @@ -224,6 +225,7 @@ CEF_GLOBAL void CefShutdown() { DCHECK(base::AtomicRefCountIsZero(&CefNavigationEntryCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero( &CefNavigationEntryVisitorCppToC::DebugObjCt)); + DCHECK(base::AtomicRefCountIsZero(&CefPdfPrintCallbackCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefPrintDialogCallbackCToCpp::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefPrintHandlerCppToC::DebugObjCt)); DCHECK(base::AtomicRefCountIsZero(&CefPrintJobCallbackCToCpp::DebugObjCt)); diff --git a/libcef_dll/wrapper_types.h b/libcef_dll/wrapper_types.h index 79ae60687..25f3fef3c 100644 --- a/libcef_dll/wrapper_types.h +++ b/libcef_dll/wrapper_types.h @@ -60,6 +60,7 @@ enum CefWrapperType { WT_MENU_MODEL, WT_NAVIGATION_ENTRY, WT_NAVIGATION_ENTRY_VISITOR, + WT_PDF_PRINT_CALLBACK, WT_POST_DATA, WT_POST_DATA_ELEMENT, WT_PRINT_DIALOG_CALLBACK, diff --git a/patch/patch.cfg b/patch/patch.cfg index 1d31f6404..78ee7b171 100644 --- a/patch/patch.cfg +++ b/patch/patch.cfg @@ -155,4 +155,10 @@ patches = [ 'name': 'ime_1610', 'path': '../ui/base/ime/', }, + { + # Enable support for print header and footer. + # https://bitbucket.org/chromiumembedded/cef/issue/1478 + 'name': 'print_header_footer_1478', + 'path': '../components/', + }, ] diff --git a/patch/patches/print_header_footer_1478.patch b/patch/patches/print_header_footer_1478.patch new file mode 100644 index 000000000..d3f292a3f --- /dev/null +++ b/patch/patches/print_header_footer_1478.patch @@ -0,0 +1,125 @@ +diff --git printing/renderer/print_web_view_helper.cc printing/renderer/print_web_view_helper.cc +index cef7a95..f05255a 100644 +--- printing/renderer/print_web_view_helper.cc ++++ printing/renderer/print_web_view_helper.cc +@@ -73,6 +73,7 @@ const double kMinDpi = 1.0; + bool g_is_preview_enabled_ = false; + #else + bool g_is_preview_enabled_ = true; ++#endif // !defined(ENABLE_PRINT_PREVIEW) + + const char kPageLoadScriptFormat[] = + "document.open(); document.write(%s); document.close();"; +@@ -87,7 +88,6 @@ void ExecuteScript(blink::WebFrame* frame, + std::string script = base::StringPrintf(script_format, json.c_str()); + frame->executeScript(blink::WebString(base::UTF8ToUTF16(script))); + } +-#endif // !defined(ENABLE_PRINT_PREVIEW) + + int GetDPI(const PrintMsg_Print_Params* print_params) { + #if defined(OS_MACOSX) +@@ -484,7 +484,6 @@ blink::WebView* FrameReference::view() { + return view_; + } + +-#if defined(ENABLE_PRINT_PREVIEW) + // static - Not anonymous so that platform implementations can use it. + void PrintWebViewHelper::PrintHeaderAndFooter( + blink::WebCanvas* canvas, +@@ -541,7 +540,6 @@ void PrintWebViewHelper::PrintHeaderAndFooter( + web_view->close(); + frame->close(); + } +-#endif // defined(ENABLE_PRINT_PREVIEW) + + // static - Not anonymous so that platform implementations can use it. + float PrintWebViewHelper::RenderPageContent(blink::WebFrame* frame, +diff --git printing/renderer/print_web_view_helper.h printing/renderer/print_web_view_helper.h +index d040dbc..72dd76e 100644 +--- printing/renderer/print_web_view_helper.h ++++ printing/renderer/print_web_view_helper.h +@@ -305,7 +305,6 @@ class PrintWebViewHelper + double* scale_factor, + PageSizeMargins* page_layout_in_points); + +-#if defined(ENABLE_PRINT_PREVIEW) + // Given the |device| and |canvas| to draw on, prints the appropriate headers + // and footers using strings from |header_footer_info| on to the canvas. + static void PrintHeaderAndFooter(blink::WebCanvas* canvas, +@@ -315,7 +314,6 @@ class PrintWebViewHelper + float webkit_scale_factor, + const PageSizeMargins& page_layout_in_points, + const PrintMsg_Print_Params& params); +-#endif // defined(ENABLE_PRINT_PREVIEW) + + bool GetPrintFrame(blink::WebLocalFrame** frame); + +diff --git printing/renderer/print_web_view_helper_linux.cc printing/renderer/print_web_view_helper_linux.cc +index 79b82e9..8d1f6f4 100644 +--- printing/renderer/print_web_view_helper_linux.cc ++++ printing/renderer/print_web_view_helper_linux.cc +@@ -169,7 +169,6 @@ void PrintWebViewHelper::PrintPageInternal( + MetafileSkiaWrapper::SetMetafileOnCanvas(*canvas, metafile); + skia::SetIsDraftMode(*canvas, is_print_ready_metafile_sent_); + +-#if defined(ENABLE_PRINT_PREVIEW) + if (params.params.display_header_footer) { + // |page_number| is 0-based, so 1 is added. + // TODO(vitalybuka) : why does it work only with 1.25? +@@ -178,7 +177,6 @@ void PrintWebViewHelper::PrintPageInternal( + scale_factor / 1.25, page_layout_in_points, + params.params); + } +-#endif // defined(ENABLE_PRINT_PREVIEW) + + RenderPageContent(frame, params.page_number, canvas_area, content_area, + scale_factor, canvas); +diff --git printing/renderer/print_web_view_helper_mac.mm printing/renderer/print_web_view_helper_mac.mm +index 7aa503c..a6413be 100644 +--- printing/renderer/print_web_view_helper_mac.mm ++++ printing/renderer/print_web_view_helper_mac.mm +@@ -125,14 +125,12 @@ void PrintWebViewHelper::RenderPage(const PrintMsg_Print_Params& params, + MetafileSkiaWrapper::SetMetafileOnCanvas(*canvas, metafile); + skia::SetIsDraftMode(*canvas, is_print_ready_metafile_sent_); + skia::SetIsPreviewMetafile(*canvas, is_preview); +-#if defined(ENABLE_PRINT_PREVIEW) + if (params.display_header_footer) { + PrintHeaderAndFooter(static_cast(canvas), + page_number + 1, + print_preview_context_.total_page_count(), *frame, + scale_factor, page_layout_in_points, params); + } +-#endif // defined(ENABLE_PRINT_PREVIEW) + RenderPageContent(frame, page_number, canvas_area, content_area, + scale_factor, static_cast(canvas)); + } +diff --git printing/renderer/print_web_view_helper_pdf_win.cc printing/renderer/print_web_view_helper_pdf_win.cc +index a121448..f2a1a0a 100644 +--- printing/renderer/print_web_view_helper_pdf_win.cc ++++ printing/renderer/print_web_view_helper_pdf_win.cc +@@ -185,14 +185,12 @@ void PrintWebViewHelper::PrintPageInternal( + MetafileSkiaWrapper::SetMetafileOnCanvas(*canvas, metafile); + skia::SetIsDraftMode(*canvas, is_print_ready_metafile_sent_); + +-#if defined(ENABLE_PRINT_PREVIEW) + if (params.params.display_header_footer) { + // |page_number| is 0-based, so 1 is added. + PrintHeaderAndFooter(canvas, params.page_number + 1, + print_preview_context_.total_page_count(), *frame, + scale_factor, page_layout_in_points, params.params); + } +-#endif // defined(ENABLE_PRINT_PREVIEW) + + float webkit_scale_factor = + RenderPageContent(frame, params.page_number, canvas_area, content_area, +diff --git resources/printing_resources.grdp resources/printing_resources.grdp +index 7213746..32b8b1e 100644 +--- resources/printing_resources.grdp ++++ resources/printing_resources.grdp +@@ -1,6 +1,4 @@ + + +- + +- + diff --git a/tests/cefclient/browser/print_handler_gtk.cc b/tests/cefclient/browser/print_handler_gtk.cc index 076c1846d..dc1b389f8 100644 --- a/tests/cefclient/browser/print_handler_gtk.cc +++ b/tests/cefclient/browser/print_handler_gtk.cc @@ -440,6 +440,17 @@ void ClientPrintHandlerGtk::OnPrintReset() { } } +CefSize ClientPrintHandlerGtk::GetPdfPaperSize(int device_units_per_inch) { + GtkPageSetup* page_setup = gtk_page_setup_new(); + + float width = gtk_page_setup_get_paper_width(page_setup, GTK_UNIT_INCH); + float height = gtk_page_setup_get_paper_height(page_setup, GTK_UNIT_INCH); + + g_object_unref(page_setup); + + return CefSize(width * device_units_per_inch, height * device_units_per_inch); +} + void ClientPrintHandlerGtk::OnDialogResponse(GtkDialog *dialog, gint response_id) { int num_matched_handlers = g_signal_handlers_disconnect_by_func( diff --git a/tests/cefclient/browser/print_handler_gtk.h b/tests/cefclient/browser/print_handler_gtk.h index 819a2f7ae..76bae4b7b 100644 --- a/tests/cefclient/browser/print_handler_gtk.h +++ b/tests/cefclient/browser/print_handler_gtk.h @@ -28,6 +28,7 @@ class ClientPrintHandlerGtk : public CefPrintHandler { const CefString& pdf_file_path, CefRefPtr callback) OVERRIDE; void OnPrintReset() OVERRIDE; + CefSize GetPdfPaperSize(int device_units_per_inch) OVERRIDE; private: void OnDialogResponse(GtkDialog *dialog, diff --git a/tests/cefclient/browser/resource.h b/tests/cefclient/browser/resource.h index f48c757a3..d4c706786 100644 --- a/tests/cefclient/browser/resource.h +++ b/tests/cefclient/browser/resource.h @@ -41,7 +41,8 @@ #define ID_TESTS_FPS_INCREASE 32713 #define ID_TESTS_FPS_DECREASE 32714 #define ID_TESTS_FPS_RESET 32715 -#define ID_TESTS_LAST 32715 +#define ID_TESTS_PRINT_TO_PDF 32716 +#define ID_TESTS_LAST 32716 #define IDC_STATIC -1 #define IDS_BINDING 1000 #define IDS_DIALOGS 1001 diff --git a/tests/cefclient/browser/root_window_gtk.cc b/tests/cefclient/browser/root_window_gtk.cc index 4f9c984df..d66466039 100644 --- a/tests/cefclient/browser/root_window_gtk.cc +++ b/tests/cefclient/browser/root_window_gtk.cc @@ -602,6 +602,7 @@ GtkWidget* RootWindowGtk::CreateMenuBar() { AddMenuEntry(test_menu, "Begin Tracing", ID_TESTS_TRACING_BEGIN); AddMenuEntry(test_menu, "End Tracing", ID_TESTS_TRACING_END); AddMenuEntry(test_menu, "Print", ID_TESTS_PRINT); + AddMenuEntry(test_menu, "Print to PDF", ID_TESTS_PRINT_TO_PDF); AddMenuEntry(test_menu, "Other Tests", ID_TESTS_OTHER_TESTS); return menu_bar; diff --git a/tests/cefclient/browser/test_runner.cc b/tests/cefclient/browser/test_runner.cc index d738542a5..bc0184184 100644 --- a/tests/cefclient/browser/test_runner.cc +++ b/tests/cefclient/browser/test_runner.cc @@ -227,7 +227,8 @@ void EndTracing(CefRefPtr browser) { // Results in a call to OnFileDialogDismissed. browser_->GetHost()->RunFileDialog( - FILE_DIALOG_SAVE, + static_cast( + FILE_DIALOG_SAVE | FILE_DIALOG_OVERWRITEPROMPT_FLAG), CefString(), // title path, std::vector(), // accept_filters @@ -235,7 +236,7 @@ void EndTracing(CefRefPtr browser) { this); } - virtual void OnFileDialogDismissed( + void OnFileDialogDismissed( int selected_accept_filter, const std::vector& file_paths) OVERRIDE { if (!file_paths.empty()) { @@ -247,7 +248,7 @@ void EndTracing(CefRefPtr browser) { } } - virtual void OnEndTracingComplete( + void OnEndTracingComplete( const CefString& tracing_file) OVERRIDE { Alert(browser_, "File \"" + tracing_file.ToString() + "\" saved successfully."); @@ -262,6 +263,71 @@ void EndTracing(CefRefPtr browser) { new Client(browser); } +void PrintToPDF(CefRefPtr browser) { + if (!CefCurrentlyOn(TID_UI)) { + // Execute on the UI thread. + CefPostTask(TID_UI, base::Bind(&PrintToPDF, browser)); + return; + } + + class Client : public CefPdfPrintCallback, + public CefRunFileDialogCallback { + public: + explicit Client(CefRefPtr browser) + : browser_(browser) { + RunDialog(); + } + + void RunDialog() { + static const char kDefaultFileName[] = "output.pdf"; + std::string path = MainContext::Get()->GetDownloadPath(kDefaultFileName); + if (path.empty()) + path = kDefaultFileName; + + std::vector accept_filters; + accept_filters.push_back(".pdf"); + + // Results in a call to OnFileDialogDismissed. + browser_->GetHost()->RunFileDialog( + static_cast( + FILE_DIALOG_SAVE | FILE_DIALOG_OVERWRITEPROMPT_FLAG), + CefString(), // title + path, + accept_filters, + 0, // selected_accept_filter + this); + } + + void OnFileDialogDismissed( + int selected_accept_filter, + const std::vector& file_paths) OVERRIDE { + if (!file_paths.empty()) { + CefPdfPrintSettings settings; + + // Show the URL in the footer. + settings.header_footer_enabled = true; + CefString(&settings.header_footer_url) = + browser_->GetMainFrame()->GetURL(); + + // Print to the selected PDF file. + browser_->GetHost()->PrintToPDF(file_paths[0], settings, this); + } + } + + void OnPdfPrintFinished(const CefString& path, bool ok) OVERRIDE { + Alert(browser_, "File \"" + path.ToString() +"\" " + + (ok ? "saved successfully." : "failed to save.")); + } + + private: + CefRefPtr browser_; + + IMPLEMENT_REFCOUNTING(Client); + }; + + new Client(browser); +} + void RunOtherTests(CefRefPtr browser) { browser->GetMainFrame()->LoadURL("http://tests/other_tests"); } @@ -389,6 +455,9 @@ void RunTest(CefRefPtr browser, int id) { case ID_TESTS_PRINT: browser->GetHost()->Print(); break; + case ID_TESTS_PRINT_TO_PDF: + PrintToPDF(browser); + break; case ID_TESTS_OTHER_TESTS: RunOtherTests(browser); break; diff --git a/tests/cefclient/cefclient_mac.mm b/tests/cefclient/cefclient_mac.mm index dfd3ede84..907dedd76 100644 --- a/tests/cefclient/cefclient_mac.mm +++ b/tests/cefclient/cefclient_mac.mm @@ -143,6 +143,7 @@ void AddMenuItem(NSMenu *menu, NSString* label, int idval) { AddMenuItem(testMenu, @"Begin Tracing", ID_TESTS_TRACING_BEGIN); AddMenuItem(testMenu, @"End Tracing", ID_TESTS_TRACING_END); AddMenuItem(testMenu, @"Print", ID_TESTS_PRINT); + AddMenuItem(testMenu, @"Print to PDF", ID_TESTS_PRINT_TO_PDF); AddMenuItem(testMenu, @"Other Tests", ID_TESTS_OTHER_TESTS); [testItem setSubmenu:testMenu]; [menubar addItem:testItem]; diff --git a/tests/cefclient/resources/win/cefclient.rc b/tests/cefclient/resources/win/cefclient.rc index 316cd3b07..388786c52 100644 --- a/tests/cefclient/resources/win/cefclient.rc +++ b/tests/cefclient/resources/win/cefclient.rc @@ -86,6 +86,7 @@ BEGIN MENUITEM "Begin Tracing", ID_TESTS_TRACING_BEGIN MENUITEM "End Tracing", ID_TESTS_TRACING_END MENUITEM "Print", ID_TESTS_PRINT + MENUITEM "Print to PDF", ID_TESTS_PRINT_TO_PDF MENUITEM "Other Tests", ID_TESTS_OTHER_TESTS END END