Add support for printing via CefBrowserHost::Print() and JavaScript window.print() (issue #505).

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@1479 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt 2013-10-23 19:30:47 +00:00
parent f248b937f9
commit bc1ea4974a
35 changed files with 1960 additions and 20 deletions

49
cef.gyp
View File

@ -439,6 +439,7 @@
[ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', {
'dependencies': [
'<(DEPTH)/build/linux/system.gyp:gtk',
'<(DEPTH)/build/linux/system.gyp:gtkprint',
],
'sources': [
'tests/cefclient/resource_util_linux.cpp',
@ -530,8 +531,9 @@
'dependencies':[
'<(DEPTH)/base/allocator/allocator.gyp:allocator',
'<(DEPTH)/build/linux/system.gyp:gtk',
'<(DEPTH)/build/linux/system.gyp:gtkprint',
],
}],
}],
],
},
{
@ -557,6 +559,7 @@
[ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', {
'dependencies': [
'<(DEPTH)/build/linux/system.gyp:gtk',
'<(DEPTH)/build/linux/system.gyp:gtkprint',
],
}],
],
@ -768,6 +771,7 @@
'<(DEPTH)/third_party/WebKit/public/platform',
'<(DEPTH)/third_party/WebKit/public/web',
# CEF grit resource includes
'<(DEPTH)/cef/libcef/resources/grit_stub',
'<(grit_out_dir)',
'<(SHARED_INTERMEDIATE_DIR)/content/browser/tracing',
'<(SHARED_INTERMEDIATE_DIR)/ui/ui_strings',
@ -831,6 +835,8 @@
'libcef/browser/browser_settings.h',
'libcef/browser/browser_urlrequest_impl.cc',
'libcef/browser/browser_urlrequest_impl.h',
'libcef/browser/chrome_browser_process_stub.cc',
'libcef/browser/chrome_browser_process_stub.h',
'libcef/browser/chrome_scheme_handler.cc',
'libcef/browser/chrome_scheme_handler.h',
'libcef/browser/content_browser_client.cc',
@ -868,6 +874,12 @@
'libcef/browser/origin_whitelist_impl.cc',
'libcef/browser/origin_whitelist_impl.h',
'libcef/browser/path_util_impl.cc',
'libcef/browser/printing/printing_message_filter.cc',
'libcef/browser/printing/printing_message_filter.h',
'libcef/browser/printing/print_view_manager.cc',
'libcef/browser/printing/print_view_manager.h',
'libcef/browser/printing/print_view_manager_base.cc',
'libcef/browser/printing/print_view_manager_base.h',
'libcef/browser/process_util_impl.cc',
'libcef/browser/proxy_stubs.cc',
'libcef/browser/render_widget_host_view_osr.cc',
@ -1004,6 +1016,28 @@
# Include sources for the loadtimes V8 extension.
'<(DEPTH)/chrome/renderer/loadtimes_extension_bindings.h',
'<(DEPTH)/chrome/renderer/loadtimes_extension_bindings.cc',
# Include sources for printing.
'<(DEPTH)/chrome/browser/printing/print_job.cc',
'<(DEPTH)/chrome/browser/printing/print_job.h',
'<(DEPTH)/chrome/browser/printing/print_job_manager.cc',
'<(DEPTH)/chrome/browser/printing/print_job_manager.h',
'<(DEPTH)/chrome/browser/printing/print_job_worker.cc',
'<(DEPTH)/chrome/browser/printing/print_job_worker.h',
'<(DEPTH)/chrome/browser/printing/print_job_worker_owner.h',
'<(DEPTH)/chrome/browser/printing/print_job_worker_owner.h',
'<(DEPTH)/chrome/browser/printing/printer_query.cc',
'<(DEPTH)/chrome/browser/printing/printer_query.h',
'<(DEPTH)/chrome/common/prerender_messages.h',
'<(DEPTH)/chrome/common/print_messages.cc',
'<(DEPTH)/chrome/common/print_messages.h',
'<(DEPTH)/chrome/renderer/prerender/prerender_helper.cc',
'<(DEPTH)/chrome/renderer/prerender/prerender_helper.h',
'<(DEPTH)/chrome/renderer/printing/print_web_view_helper.cc',
'<(DEPTH)/chrome/renderer/printing/print_web_view_helper.h',
# Include header for stub creation (BrowserProcess) so print_job_worker can
# determine the current locale.
'<(DEPTH)/chrome/browser/browser_process.cc',
'<(DEPTH)/chrome/browser/browser_process.h',
],
'conditions': [
['OS=="win"', {
@ -1024,6 +1058,8 @@
'<(DEPTH)/ui/views/controls/menu/menu_listener.h',
'<(DEPTH)/ui/views/controls/menu/native_menu_win.cc',
'<(DEPTH)/ui/views/controls/menu/native_menu_win.h',
# Include sources for printing.
'<(DEPTH)/chrome/renderer/printing/print_web_view_helper_win.cc',
],
}],
[ 'OS=="mac"', {
@ -1045,9 +1081,14 @@
'libcef/browser/text_input_client_osr_mac.h',
'libcef/browser/web_contents_view_osr.cc',
'libcef/browser/web_contents_view_osr.h',
# Include sources for printing.
'<(DEPTH)/chrome/renderer/printing/print_web_view_helper_mac.mm',
],
}],
[ 'OS=="linux" or OS=="freebsd" or OS=="openbsd"', {
'dependencies':[
'<(DEPTH)/build/linux/system.gyp:gtkprint',
],
'sources': [
'<@(includes_linux)',
'libcef/browser/browser_host_impl_gtk.cc',
@ -1065,6 +1106,10 @@
'<(DEPTH)/chrome/browser/ui/gtk/menu_gtk.h',
'<(DEPTH)/chrome/browser/ui/views/event_utils.cc',
'<(DEPTH)/chrome/browser/ui/views/event_utils.h',
#Include sources for printing.
'<(DEPTH)/chrome/browser/printing/print_dialog_gtk.cc',
'<(DEPTH)/chrome/browser/printing/print_dialog_gtk.h',
'<(DEPTH)/chrome/renderer/printing/print_web_view_helper_linux.cc',
],
}],
],
@ -1334,7 +1379,7 @@
# gtk requires gmodule, but it does not list it as a dependency
# in some misconfigured systems.
# gtkglext is required by the cefclient OSR example.
'gtk_packages': 'gmodule-2.0 gtk+-2.0 gthread-2.0 gtkglext-1.0',
'gtk_packages': 'gmodule-2.0 gtk+-2.0 gthread-2.0 gtkglext-1.0 gtk+-unix-print-2.0',
},
'direct_dependent_settings': {
'cflags': [

View File

@ -319,6 +319,11 @@ typedef struct _cef_browser_host_t {
void (CEF_CALLBACK *start_download)(struct _cef_browser_host_t* self,
const cef_string_t* url);
///
// Print the current browser contents.
///
void (CEF_CALLBACK *print)(struct _cef_browser_host_t* self);
///
// Set whether mouse cursor change is disabled.
///

View File

@ -366,6 +366,12 @@ class CefBrowserHost : public virtual CefBase {
/*--cef()--*/
virtual void StartDownload(const CefString& url) =0;
///
// Print the current browser contents.
///
/*--cef()--*/
virtual void Print() =0;
///
// Set whether mouse cursor change is disabled.
///
@ -485,7 +491,6 @@ class CefBrowserHost : public virtual CefBase {
///
/*--cef()--*/
virtual void HandleKeyEventAfterTextInputClient(CefEventHandle keyEvent) =0;
};
#endif // CEF_INCLUDE_CEF_BROWSER_H_

View File

@ -17,6 +17,7 @@
#include "libcef/browser/devtools_delegate.h"
#include "libcef/browser/media_capture_devices_dispatcher.h"
#include "libcef/browser/navigate_params.h"
#include "libcef/browser/printing/print_view_manager.h"
#include "libcef/browser/render_widget_host_view_osr.h"
#include "libcef/browser/request_context_impl.h"
#include "libcef/browser/scheme_handler.h"
@ -603,6 +604,18 @@ void CefBrowserHostImpl::StartDownload(const CefString& url) {
manager->DownloadUrl(params.Pass());
}
void CefBrowserHostImpl::Print() {
if (CEF_CURRENTLY_ON_UIT()) {
if (!web_contents_)
return;
printing::PrintViewManager::FromWebContents(
web_contents_.get())->PrintNow();
} else {
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefBrowserHostImpl::Print, this));
}
}
void CefBrowserHostImpl::SetMouseCursorChangeDisabled(bool disabled) {
base::AutoLock lock_scope(state_lock_);
mouse_cursor_change_disabled_ = disabled;
@ -2114,6 +2127,8 @@ CefBrowserHostImpl::CefBrowserHostImpl(
CefString(), CefString(),
CefFrameHostImpl::kInvalidFrameId);
printing::PrintViewManager::CreateForWebContents(web_contents_.get());
// Make sure RenderViewCreated is called at least one time.
RenderViewCreated(web_contents->GetRenderViewHost());

View File

@ -124,6 +124,7 @@ class CefBrowserHostImpl : public CefBrowserHost,
const std::vector<CefString>& accept_types,
CefRefPtr<CefRunFileDialogCallback> callback) OVERRIDE;
virtual void StartDownload(const CefString& url) OVERRIDE;
virtual void Print() OVERRIDE;
virtual void SetMouseCursorChangeDisabled(bool disabled) OVERRIDE;
virtual bool IsMouseCursorChangeDisabled() OVERRIDE;
virtual bool IsWindowRenderingDisabled() OVERRIDE;

View File

@ -26,6 +26,10 @@
#include "ui/base/resource/resource_bundle.h"
#include "v8/include/v8.h"
#if defined(OS_LINUX)
#include "chrome/browser/printing/print_dialog_gtk.h"
#endif
CefBrowserMainParts::CefBrowserMainParts(
const content::MainFunctionParams& parameters)
: BrowserMainParts(),
@ -48,6 +52,11 @@ void CefBrowserMainParts::PostMainMessageLoopStart() {
// CEF's internal handling of "chrome://tracing".
content::WebUIControllerFactory::UnregisterFactoryForTesting(
content::ContentWebUIControllerFactory::GetInstance());
#if defined(OS_LINUX)
printing::PrintingContextGtk::SetCreatePrintDialogFunction(
&PrintDialogGtk::CreatePrintDialog);
#endif
}
int CefBrowserMainParts::PreCreateThreads() {

View File

@ -29,6 +29,8 @@ PrefService* CefBrowserPrefStore::CreateService() {
CefMediaCaptureDevicesDispatcher::RegisterPrefs(registry);
PrefProxyConfigTrackerImpl::RegisterPrefs(registry);
registry->RegisterBooleanPref(prefs::kPrintingEnabled, true);
return builder.Create(registry);
}

View File

@ -0,0 +1,271 @@
// Copyright (c) 2013 The Chromium Embedded Framework Authors.
// Portions (c) 2011 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 "libcef/browser/chrome_browser_process_stub.h"
#include "libcef/browser/context.h"
#include "base/memory/scoped_ptr.h"
#include "ui/message_center/message_center.h"
ChromeBrowserProcessStub::ChromeBrowserProcessStub()
: locale_("en-US") {
}
ChromeBrowserProcessStub::~ChromeBrowserProcessStub() {
g_browser_process = NULL;
}
void ChromeBrowserProcessStub::ResourceDispatcherHostCreated() {
NOTIMPLEMENTED();
};
void ChromeBrowserProcessStub::EndSession() {
NOTIMPLEMENTED();
};
MetricsService* ChromeBrowserProcessStub::metrics_service() {
NOTIMPLEMENTED();
return NULL;
}
IOThread* ChromeBrowserProcessStub::io_thread() {
NOTIMPLEMENTED();
return NULL;
}
WatchDogThread* ChromeBrowserProcessStub::watchdog_thread() {
NOTIMPLEMENTED();
return NULL;
}
ProfileManager* ChromeBrowserProcessStub::profile_manager() {
NOTIMPLEMENTED();
return NULL;
}
PrefService* ChromeBrowserProcessStub::local_state() {
NOTIMPLEMENTED();
return NULL;
}
net::URLRequestContextGetter*
ChromeBrowserProcessStub::system_request_context() {
NOTIMPLEMENTED();
return NULL;
}
chrome_variations::VariationsService*
ChromeBrowserProcessStub::variations_service() {
NOTIMPLEMENTED();
return NULL;
}
BrowserProcessPlatformPart* ChromeBrowserProcessStub::platform_part() {
NOTIMPLEMENTED();
return NULL;
}
extensions::EventRouterForwarder*
ChromeBrowserProcessStub::extension_event_router_forwarder() {
NOTIMPLEMENTED();
return NULL;
}
NotificationUIManager* ChromeBrowserProcessStub::notification_ui_manager() {
NOTIMPLEMENTED();
return NULL;
}
message_center::MessageCenter* ChromeBrowserProcessStub::message_center() {
NOTIMPLEMENTED();
return NULL;
}
policy::BrowserPolicyConnector*
ChromeBrowserProcessStub::browser_policy_connector() {
NOTIMPLEMENTED();
return NULL;
}
policy::PolicyService* ChromeBrowserProcessStub::policy_service() {
NOTIMPLEMENTED();
return NULL;
}
IconManager* ChromeBrowserProcessStub::icon_manager() {
NOTIMPLEMENTED();
return NULL;
}
GLStringManager* ChromeBrowserProcessStub::gl_string_manager() {
NOTIMPLEMENTED();
return NULL;
}
GpuModeManager* ChromeBrowserProcessStub::gpu_mode_manager() {
NOTIMPLEMENTED();
return NULL;
}
RenderWidgetSnapshotTaker*
ChromeBrowserProcessStub::GetRenderWidgetSnapshotTaker() {
NOTIMPLEMENTED();
return NULL;
}
AutomationProviderList*
ChromeBrowserProcessStub::GetAutomationProviderList() {
NOTIMPLEMENTED();
return NULL;
}
void ChromeBrowserProcessStub::CreateDevToolsHttpProtocolHandler(
chrome::HostDesktopType host_desktop_type,
const std::string& ip,
int port,
const std::string& frontend_url) {
}
unsigned int ChromeBrowserProcessStub::AddRefModule() {
NOTIMPLEMENTED();
return 0;
}
unsigned int ChromeBrowserProcessStub::ReleaseModule() {
NOTIMPLEMENTED();
return 0;
}
bool ChromeBrowserProcessStub::IsShuttingDown() {
NOTIMPLEMENTED();
return false;
}
printing::PrintJobManager* ChromeBrowserProcessStub::print_job_manager() {
return CefContext::Get()->print_job_manager();
}
printing::PrintPreviewDialogController*
ChromeBrowserProcessStub::print_preview_dialog_controller() {
NOTIMPLEMENTED();
return NULL;
}
printing::BackgroundPrintingManager*
ChromeBrowserProcessStub::background_printing_manager() {
NOTIMPLEMENTED();
return NULL;
}
IntranetRedirectDetector*
ChromeBrowserProcessStub::intranet_redirect_detector() {
NOTIMPLEMENTED();
return NULL;
}
const std::string &ChromeBrowserProcessStub::GetApplicationLocale() {
DCHECK(!locale_.empty());
return locale_;
}
void ChromeBrowserProcessStub::SetApplicationLocale(const std::string& locale) {
locale_ = locale;
}
DownloadStatusUpdater* ChromeBrowserProcessStub::download_status_updater() {
NOTIMPLEMENTED();
return NULL;
}
DownloadRequestLimiter* ChromeBrowserProcessStub::download_request_limiter() {
NOTIMPLEMENTED();
return NULL;
}
BackgroundModeManager* ChromeBrowserProcessStub::background_mode_manager() {
NOTIMPLEMENTED();
return NULL;
}
void ChromeBrowserProcessStub::set_background_mode_manager_for_test(
scoped_ptr<BackgroundModeManager> manager) {
NOTIMPLEMENTED();
}
StatusTray* ChromeBrowserProcessStub::status_tray() {
NOTIMPLEMENTED();
return NULL;
}
SafeBrowsingService* ChromeBrowserProcessStub::safe_browsing_service() {
NOTIMPLEMENTED();
return NULL;
}
safe_browsing::ClientSideDetectionService*
ChromeBrowserProcessStub::safe_browsing_detection_service() {
NOTIMPLEMENTED();
return NULL;
}
#if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
void ChromeBrowserProcessStub::StartAutoupdateTimer() {
}
#endif
ChromeNetLog* ChromeBrowserProcessStub::net_log() {
NOTIMPLEMENTED();
return NULL;
}
prerender::PrerenderTracker* ChromeBrowserProcessStub::prerender_tracker() {
NOTIMPLEMENTED();
return NULL;
}
ComponentUpdateService* ChromeBrowserProcessStub::component_updater() {
NOTIMPLEMENTED();
return NULL;
}
CRLSetFetcher* ChromeBrowserProcessStub::crl_set_fetcher() {
NOTIMPLEMENTED();
return NULL;
}
PnaclComponentInstaller*
ChromeBrowserProcessStub::pnacl_component_installer() {
NOTIMPLEMENTED();
return NULL;
}
BookmarkPromptController*
ChromeBrowserProcessStub::bookmark_prompt_controller() {
NOTIMPLEMENTED();
return NULL;
}
MediaFileSystemRegistry*
ChromeBrowserProcessStub::media_file_system_registry() {
NOTIMPLEMENTED();
return NULL;
}
bool ChromeBrowserProcessStub::created_local_state() const {
NOTIMPLEMENTED();
return false;
}
StorageMonitor* ChromeBrowserProcessStub::storage_monitor() {
NOTIMPLEMENTED();
return NULL;
}
#if defined(ENABLE_WEBRTC)
WebRtcLogUploader* ChromeBrowserProcessStub::webrtc_log_uploader() {
NOTIMPLEMENTED();
return NULL;
}
#endif

View File

@ -0,0 +1,103 @@
// Copyright (c) 2013 The Chromium Embedded Framework Authors.
// Portions (c) 2011 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 CEF_LIBCEF_BROWSER_CHROME_BROWSER_PROCESS_STUB_H_
#define CEF_LIBCEF_BROWSER_CHROME_BROWSER_PROCESS_STUB_H_
#include <string>
#include "chrome/browser/browser_process.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
// This file provides a stub implementation of chrome::BrowserProcess so that
// PrintJobWorker can determine the current locale.
class BackgroundModeManager {
public:
BackgroundModeManager();
virtual ~BackgroundModeManager();
private:
DISALLOW_COPY_AND_ASSIGN(BackgroundModeManager);
};
class ChromeBrowserProcessStub : public BrowserProcess {
public:
ChromeBrowserProcessStub();
virtual ~ChromeBrowserProcessStub();
// BrowserProcess implementation.
virtual void ResourceDispatcherHostCreated() OVERRIDE;
virtual void EndSession() OVERRIDE;
virtual MetricsService* metrics_service() OVERRIDE;
virtual IOThread* io_thread() OVERRIDE;
virtual WatchDogThread* watchdog_thread() OVERRIDE;
virtual ProfileManager* profile_manager() OVERRIDE;
virtual PrefService* local_state() OVERRIDE;
virtual net::URLRequestContextGetter* system_request_context() OVERRIDE;
virtual chrome_variations::VariationsService* variations_service() OVERRIDE;
virtual BrowserProcessPlatformPart* platform_part() OVERRIDE;
virtual extensions::EventRouterForwarder*
extension_event_router_forwarder() OVERRIDE;
virtual NotificationUIManager* notification_ui_manager() OVERRIDE;
virtual message_center::MessageCenter* message_center() OVERRIDE;
virtual policy::BrowserPolicyConnector* browser_policy_connector() OVERRIDE;
virtual policy::PolicyService* policy_service() OVERRIDE;
virtual IconManager* icon_manager() OVERRIDE;
virtual GLStringManager* gl_string_manager() OVERRIDE;
virtual GpuModeManager* gpu_mode_manager() OVERRIDE;
virtual RenderWidgetSnapshotTaker* GetRenderWidgetSnapshotTaker() OVERRIDE;
virtual AutomationProviderList* GetAutomationProviderList() OVERRIDE;
virtual void CreateDevToolsHttpProtocolHandler(
chrome::HostDesktopType host_desktop_type,
const std::string& ip,
int port,
const std::string& frontend_url) OVERRIDE;
virtual unsigned int AddRefModule() OVERRIDE;
virtual unsigned int ReleaseModule() OVERRIDE;
virtual bool IsShuttingDown() OVERRIDE;
virtual printing::PrintJobManager* print_job_manager() OVERRIDE;
virtual printing::PrintPreviewDialogController*
print_preview_dialog_controller() OVERRIDE;
virtual printing::BackgroundPrintingManager*
background_printing_manager() OVERRIDE;
virtual IntranetRedirectDetector* intranet_redirect_detector() OVERRIDE;
virtual const std::string& GetApplicationLocale() OVERRIDE;
virtual void SetApplicationLocale(const std::string& locale) OVERRIDE;
virtual DownloadStatusUpdater* download_status_updater() OVERRIDE;
virtual DownloadRequestLimiter* download_request_limiter() OVERRIDE;
virtual BackgroundModeManager* background_mode_manager() OVERRIDE;
virtual void set_background_mode_manager_for_test(
scoped_ptr<BackgroundModeManager> manager) OVERRIDE;
virtual StatusTray* status_tray() OVERRIDE;
virtual SafeBrowsingService* safe_browsing_service() OVERRIDE;
virtual safe_browsing::ClientSideDetectionService*
safe_browsing_detection_service() OVERRIDE;
#if (defined(OS_WIN) || defined(OS_LINUX)) && !defined(OS_CHROMEOS)
virtual void StartAutoupdateTimer() OVERRIDE;
#endif
virtual ChromeNetLog* net_log() OVERRIDE;
virtual prerender::PrerenderTracker* prerender_tracker() OVERRIDE;
virtual ComponentUpdateService* component_updater() OVERRIDE;
virtual CRLSetFetcher* crl_set_fetcher() OVERRIDE;
virtual PnaclComponentInstaller* pnacl_component_installer() OVERRIDE;
virtual BookmarkPromptController* bookmark_prompt_controller() OVERRIDE;
virtual MediaFileSystemRegistry*
media_file_system_registry() OVERRIDE;
virtual bool created_local_state() const OVERRIDE;
virtual StorageMonitor* storage_monitor() OVERRIDE;
#if defined(ENABLE_WEBRTC)
virtual WebRtcLogUploader* webrtc_log_uploader() OVERRIDE;
#endif
private:
std::string locale_;
DISALLOW_COPY_AND_ASSIGN(ChromeBrowserProcessStub);
};
#endif // CEF_LIBCEF_BROWSER_CHROME_BROWSER_PROCESS_STUB_H_

View File

@ -15,6 +15,7 @@
#include "libcef/browser/browser_settings.h"
#include "libcef/browser/chrome_scheme_handler.h"
#include "libcef/browser/media_capture_devices_dispatcher.h"
#include "libcef/browser/printing/printing_message_filter.h"
#include "libcef/browser/resource_dispatcher_host_delegate.h"
#include "libcef/browser/speech_recognition_manager_delegate.h"
#include "libcef/browser/thread_util.h"
@ -454,6 +455,8 @@ CefContentBrowserClient::OverrideCreateWebContentsView(
void CefContentBrowserClient::RenderProcessHostCreated(
content::RenderProcessHost* host) {
host->GetChannel()->AddFilter(new CefBrowserMessageFilter(host));
host->AddFilter(new PrintingMessageFilter(host->GetID()));
AddBrowserContextReference(
static_cast<CefBrowserContext*>(host->GetBrowserContext()));
}

View File

@ -8,6 +8,7 @@
#include "libcef/browser/browser_info.h"
#include "libcef/browser/browser_main.h"
#include "libcef/browser/browser_message_loop.h"
#include "libcef/browser/chrome_browser_process_stub.h"
#include "libcef/browser/content_browser_client.h"
#include "libcef/browser/scheme_handler.h"
#include "libcef/browser/thread_util.h"
@ -19,6 +20,7 @@
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/synchronization/waitable_event.h"
#include "chrome/browser/printing/print_job_manager.h"
#include "content/public/app/content_main.h"
#include "content/public/app/content_main_runner.h"
#include "content/public/browser/notification_service.h"
@ -44,13 +46,13 @@ CefContext* g_context = NULL;
// CefShutdown() has not been explicitly called.
class CefForceShutdown {
public:
~CefForceShutdown() {
if (g_context) {
g_context->Shutdown();
delete g_context;
g_context = NULL;
}
}
~CefForceShutdown() {
if (g_context) {
g_context->Shutdown();
delete g_context;
g_context = NULL;
}
}
} g_force_shutdown;
} // namespace
@ -102,6 +104,8 @@ bool CefInitialize(const CefMainArgs& args,
return false;
}
g_browser_process = new ChromeBrowserProcessStub();
// Create the new global context object.
g_context = new CefContext();
@ -267,9 +271,13 @@ bool CefContext::Initialize(const CefMainArgs& args,
initialized_ = true;
// Continue initialization on the UI thread.
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefContext::OnContextInitialized, base::Unretained(this)));
if (CEF_CURRENTLY_ON_UIT()) {
OnContextInitialized();
} else {
// Continue initialization on the UI thread.
CEF_POST_TASK(CEF_UIT,
base::Bind(&CefContext::OnContextInitialized, base::Unretained(this)));
}
return true;
}
@ -329,6 +337,9 @@ void CefContext::OnContextInitialized() {
registrar_->Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
content::NotificationService::AllBrowserContextsAndSources());
// Must be created after the NotificationService.
print_job_manager_.reset(new printing::PrintJobManager());
// Notify the handler.
CefRefPtr<CefApp> app = CefContentClient::Get()->application();
if (app.get()) {
@ -343,6 +354,12 @@ void CefContext::FinishShutdownOnUIThread(
base::WaitableEvent* uithread_shutdown_event) {
CEF_REQUIRE_UIT();
// Wait for the pending print jobs to finish. Don't do this later, since
// this might cause a nested message loop to run, and we don't want pending
// tasks to run once teardown has started.
print_job_manager_->Shutdown();
print_job_manager_.reset(NULL);
CefContentBrowserClient::Get()->DestroyAllBrowsers();
registrar_.reset();

View File

@ -27,6 +27,10 @@ namespace content {
class ContentMainRunner;
}
namespace printing {
class PrintJobManager;
}
class CefBrowserHostImpl;
class CefMainDelegate;
class CefTraceSubscriber;
@ -61,6 +65,10 @@ class CefContext : public content::NotificationObserver {
const CefSettings& settings() const { return settings_; }
printing::PrintJobManager* print_job_manager() const {
return print_job_manager_.get();
}
CefTraceSubscriber* GetTraceSubscriber();
private:
@ -95,6 +103,7 @@ class CefContext : public content::NotificationObserver {
// Only accessed on the UI Thread.
scoped_ptr<content::NotificationRegistrar> registrar_;
scoped_ptr<printing::PrintJobManager> print_job_manager_;
};
// Helper macro that returns true if the global context is in a valid state.

View File

@ -0,0 +1,64 @@
// 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 "libcef/browser/printing/print_view_manager.h"
#include <map>
#include "base/bind.h"
#include "base/lazy_instance.h"
#include "base/metrics/histogram.h"
#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/common/print_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
#include "printing/print_destination_interface.h"
using content::BrowserThread;
DEFINE_WEB_CONTENTS_USER_DATA_KEY(printing::PrintViewManager);
namespace printing {
PrintViewManager::PrintViewManager(content::WebContents* web_contents)
: PrintViewManagerBase(web_contents) {
}
PrintViewManager::~PrintViewManager() {
}
bool PrintViewManager::PrintForSystemDialogNow() {
return PrintNowInternal(new PrintMsg_PrintForSystemDialog(routing_id()));
}
bool PrintViewManager::PrintToDestination() {
// TODO(mad): Remove this once we can send user metrics from the metro driver.
// crbug.com/142330
UMA_HISTOGRAM_ENUMERATION("Metro.Print", 0, 2);
// TODO(mad): Use a passed in destination interface instead.
g_browser_process->print_job_manager()->queue()->SetDestination(
printing::CreatePrintDestination());
return PrintNowInternal(new PrintMsg_PrintPages(routing_id()));
}
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_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled ? true : PrintViewManagerBase::OnMessageReceived(message);
}
} // namespace printing

View File

@ -0,0 +1,51 @@
// 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 CEF_LIBCEF_BROWSER_PRINTING_PRINT_VIEW_MANAGER_H_
#define CEF_LIBCEF_BROWSER_PRINTING_PRINT_VIEW_MANAGER_H_
#include "libcef/browser/printing/print_view_manager_base.h"
#include "content/public/browser/web_contents_user_data.h"
namespace content {
class RenderProcessHost;
}
namespace printing {
// Manages the print commands for a WebContents.
class PrintViewManager : public PrintViewManagerBase,
public content::WebContentsUserData<PrintViewManager> {
public:
virtual ~PrintViewManager();
// Same as PrintNow(), but for the case where a user prints with the system
// dialog from print preview.
bool PrintForSystemDialogNow();
// Same as PrintNow(), but for the case where we want to send the result to
// another destination.
// TODO(mad) Add an argument so we can pass the destination interface.
bool PrintToDestination();
// content::WebContentsObserver implementation.
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
// content::WebContentsObserver implementation.
// Terminates or cancels the print job if one was pending.
virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
private:
explicit PrintViewManager(content::WebContents* web_contents);
friend class content::WebContentsUserData<PrintViewManager>;
// IPC Message handlers.
void OnDidShowPrintDialog();
DISALLOW_COPY_AND_ASSIGN(PrintViewManager);
};
} // namespace printing
#endif // CEF_LIBCEF_BROWSER_PRINTING_PRINT_VIEW_MANAGER_H_

View File

@ -0,0 +1,522 @@
// Copyright 2013 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 "libcef/browser/printing/print_view_manager_base.h"
#include <map>
#include "libcef/browser/content_browser_client.h"
#include "base/bind.h"
#include "base/memory/scoped_ptr.h"
#include "base/prefs/pref_service.h"
#include "base/strings/utf_string_conversions.h"
#include "base/timer/timer.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/printing/print_job.h"
#include "chrome/browser/printing/print_job_manager.h"
#include "chrome/browser/printing/printer_query.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/print_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "grit/generated_resources.h"
#include "printing/metafile_impl.h"
#include "printing/printed_document.h"
#include "ui/base/l10n/l10n_util.h"
#if defined(OS_WIN)
#include "base/command_line.h"
#include "chrome/common/chrome_switches.h"
#endif
using base::TimeDelta;
using content::BrowserThread;
#if defined(OS_WIN)
// Limits memory usage by raster to 64 MiB.
const int kMaxRasterSizeInPixels = 16*1024*1024;
#endif
namespace printing {
PrintViewManagerBase::PrintViewManagerBase(content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
number_pages_(0),
printing_succeeded_(false),
inside_inner_message_loop_(false),
cookie_(0),
queue_(g_browser_process->print_job_manager()->queue()) {
DCHECK(queue_);
#if defined(OS_POSIX) && !defined(OS_MACOSX)
expecting_first_page_ = true;
#endif
printing_enabled_.Init(
prefs::kPrintingEnabled,
CefContentBrowserClient::Get()->pref_service(),
base::Bind(&PrintViewManagerBase::UpdateScriptedPrintingBlocked,
base::Unretained(this)));
}
PrintViewManagerBase::~PrintViewManagerBase() {
ReleasePrinterQuery();
DisconnectFromCurrentPrintJob();
}
bool PrintViewManagerBase::PrintNow() {
return PrintNowInternal(new PrintMsg_PrintPages(routing_id()));
}
void PrintViewManagerBase::UpdateScriptedPrintingBlocked() {
Send(new PrintMsg_SetScriptedPrintingBlocked(
routing_id(),
!printing_enabled_.GetValue()));
}
void PrintViewManagerBase::NavigationStopped() {
// Cancel the current job, wait for the worker to finish.
TerminatePrintJob(true);
}
void PrintViewManagerBase::RenderProcessGone(base::TerminationStatus status) {
ReleasePrinterQuery();
if (!print_job_.get())
return;
scoped_refptr<PrintedDocument> document(print_job_->document());
if (document.get()) {
// If IsComplete() returns false, the document isn't completely rendered.
// Since our renderer is gone, there's nothing to do, cancel it. Otherwise,
// the print job may finish without problem.
TerminatePrintJob(!document->IsComplete());
}
}
string16 PrintViewManagerBase::RenderSourceName() {
string16 name(web_contents()->GetTitle());
if (name.empty())
name = l10n_util::GetStringUTF16(IDS_DEFAULT_PRINT_DOCUMENT_TITLE);
return name;
}
void PrintViewManagerBase::OnDidGetPrintedPagesCount(int cookie,
int number_pages) {
DCHECK_GT(cookie, 0);
DCHECK_GT(number_pages, 0);
number_pages_ = number_pages;
OpportunisticallyCreatePrintJob(cookie);
}
void PrintViewManagerBase::OnDidGetDocumentCookie(int cookie) {
cookie_ = cookie;
}
void PrintViewManagerBase::OnDidPrintPage(
const PrintHostMsg_DidPrintPage_Params& params) {
if (!OpportunisticallyCreatePrintJob(params.document_cookie))
return;
PrintedDocument* document = print_job_->document();
if (!document || params.document_cookie != document->cookie()) {
// Out of sync. It may happen since we are completely asynchronous. Old
// spurious messages can be received if one of the processes is overloaded.
return;
}
#if defined(OS_WIN) || defined(OS_MACOSX)
const bool metafile_must_be_valid = true;
#elif defined(OS_POSIX)
const bool metafile_must_be_valid = expecting_first_page_;
expecting_first_page_ = false;
#endif
base::SharedMemory shared_buf(params.metafile_data_handle, true);
if (metafile_must_be_valid) {
if (!shared_buf.Map(params.data_size)) {
NOTREACHED() << "couldn't map";
web_contents()->Stop();
return;
}
}
scoped_ptr<NativeMetafile> metafile(new NativeMetafile);
if (metafile_must_be_valid) {
if (!metafile->InitFromData(shared_buf.memory(), params.data_size)) {
NOTREACHED() << "Invalid metafile header";
web_contents()->Stop();
return;
}
}
#if defined(OS_WIN)
bool big_emf = (params.data_size && params.data_size >= kMetafileMaxSize);
const CommandLine* cmdline = CommandLine::ForCurrentProcess();
int raster_size = std::min(params.page_size.GetArea(),
kMaxRasterSizeInPixels);
if (big_emf || (cmdline && cmdline->HasSwitch(switches::kPrintRaster))) {
scoped_ptr<NativeMetafile> raster_metafile(
metafile->RasterizeMetafile(raster_size));
if (raster_metafile.get()) {
metafile.swap(raster_metafile);
} else if (big_emf) {
// Don't fall back to emf here.
NOTREACHED() << "size:" << params.data_size;
TerminatePrintJob(true);
web_contents()->Stop();
return;
}
}
#endif
// Update the rendered document. It will send notifications to the listener.
document->SetPage(params.page_number,
metafile.release(),
params.actual_shrink,
params.page_size,
params.content_area);
ShouldQuitFromInnerMessageLoop();
}
void PrintViewManagerBase::OnPrintingFailed(int cookie) {
if (cookie != cookie_) {
NOTREACHED();
return;
}
ReleasePrinterQuery();
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_PRINT_JOB_RELEASED,
content::Source<content::WebContents>(web_contents()),
content::NotificationService::NoDetails());
}
void PrintViewManagerBase::DidStartLoading(
content::RenderViewHost* render_view_host) {
UpdateScriptedPrintingBlocked();
}
bool PrintViewManagerBase::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PrintViewManagerBase, message)
IPC_MESSAGE_HANDLER(PrintHostMsg_DidGetPrintedPagesCount,
OnDidGetPrintedPagesCount)
IPC_MESSAGE_HANDLER(PrintHostMsg_DidGetDocumentCookie,
OnDidGetDocumentCookie)
IPC_MESSAGE_HANDLER(PrintHostMsg_DidPrintPage, OnDidPrintPage)
IPC_MESSAGE_HANDLER(PrintHostMsg_PrintingFailed, OnPrintingFailed)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void PrintViewManagerBase::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
switch (type) {
case chrome::NOTIFICATION_PRINT_JOB_EVENT: {
OnNotifyPrintJobEvent(*content::Details<JobEventDetails>(details).ptr());
break;
}
default: {
NOTREACHED();
break;
}
}
}
void PrintViewManagerBase::OnNotifyPrintJobEvent(
const JobEventDetails& event_details) {
switch (event_details.type()) {
case JobEventDetails::FAILED: {
TerminatePrintJob(true);
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_PRINT_JOB_RELEASED,
content::Source<content::WebContents>(web_contents()),
content::NotificationService::NoDetails());
break;
}
case JobEventDetails::USER_INIT_DONE:
case JobEventDetails::DEFAULT_INIT_DONE:
case JobEventDetails::USER_INIT_CANCELED: {
NOTREACHED();
break;
}
case JobEventDetails::ALL_PAGES_REQUESTED: {
ShouldQuitFromInnerMessageLoop();
break;
}
case JobEventDetails::NEW_DOC:
case JobEventDetails::NEW_PAGE:
case JobEventDetails::PAGE_DONE:
case JobEventDetails::DOC_DONE: {
// Don't care about the actual printing process.
break;
}
case JobEventDetails::JOB_DONE: {
// Printing is done, we don't need it anymore.
// print_job_->is_job_pending() may still be true, depending on the order
// of object registration.
printing_succeeded_ = true;
ReleasePrintJob();
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_PRINT_JOB_RELEASED,
content::Source<content::WebContents>(web_contents()),
content::NotificationService::NoDetails());
break;
}
default: {
NOTREACHED();
break;
}
}
}
bool PrintViewManagerBase::RenderAllMissingPagesNow() {
if (!print_job_.get() || !print_job_->is_job_pending())
return false;
// We can't print if there is no renderer.
if (!web_contents() ||
!web_contents()->GetRenderViewHost() ||
!web_contents()->GetRenderViewHost()->IsRenderViewLive()) {
return false;
}
// Is the document already complete?
if (print_job_->document() && print_job_->document()->IsComplete()) {
printing_succeeded_ = true;
return true;
}
// WebContents is either dying or a second consecutive request to print
// happened before the first had time to finish. We need to render all the
// pages in an hurry if a print_job_ is still pending. No need to wait for it
// to actually spool the pages, only to have the renderer generate them. Run
// a message loop until we get our signal that the print job is satisfied.
// PrintJob will send a ALL_PAGES_REQUESTED after having received all the
// pages it needs. MessageLoop::current()->Quit() will be called as soon as
// print_job_->document()->IsComplete() is true on either ALL_PAGES_REQUESTED
// or in DidPrintPage(). The check is done in
// ShouldQuitFromInnerMessageLoop().
// BLOCKS until all the pages are received. (Need to enable recursive task)
if (!RunInnerMessageLoop()) {
// This function is always called from DisconnectFromCurrentPrintJob() so we
// know that the job will be stopped/canceled in any case.
return false;
}
return true;
}
void PrintViewManagerBase::ShouldQuitFromInnerMessageLoop() {
// Look at the reason.
DCHECK(print_job_->document());
if (print_job_->document() &&
print_job_->document()->IsComplete() &&
inside_inner_message_loop_) {
// We are in a message loop created by RenderAllMissingPagesNow. Quit from
// it.
base::MessageLoop::current()->Quit();
inside_inner_message_loop_ = false;
}
}
bool PrintViewManagerBase::CreateNewPrintJob(PrintJobWorkerOwner* job) {
DCHECK(!inside_inner_message_loop_);
// Disconnect the current print_job_.
DisconnectFromCurrentPrintJob();
// We can't print if there is no renderer.
if (!web_contents()->GetRenderViewHost() ||
!web_contents()->GetRenderViewHost()->IsRenderViewLive()) {
return false;
}
// Ask the renderer to generate the print preview, create the print preview
// view and switch to it, initialize the printer and show the print dialog.
DCHECK(!print_job_.get());
DCHECK(job);
if (!job)
return false;
print_job_ = new PrintJob();
print_job_->Initialize(job, this, number_pages_);
registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT,
content::Source<PrintJob>(print_job_.get()));
printing_succeeded_ = false;
return true;
}
void PrintViewManagerBase::DisconnectFromCurrentPrintJob() {
// Make sure all the necessary rendered page are done. Don't bother with the
// return value.
bool result = RenderAllMissingPagesNow();
// Verify that assertion.
if (print_job_.get() &&
print_job_->document() &&
!print_job_->document()->IsComplete()) {
DCHECK(!result);
// That failed.
TerminatePrintJob(true);
} else {
// DO NOT wait for the job to finish.
ReleasePrintJob();
}
#if defined(OS_POSIX) && !defined(OS_MACOSX)
expecting_first_page_ = true;
#endif
}
void PrintViewManagerBase::PrintingDone(bool success) {
if (!print_job_.get())
return;
Send(new PrintMsg_PrintingDone(routing_id(), success));
}
void PrintViewManagerBase::TerminatePrintJob(bool cancel) {
if (!print_job_.get())
return;
if (cancel) {
// We don't need the metafile data anymore because the printing is canceled.
print_job_->Cancel();
inside_inner_message_loop_ = false;
} else {
DCHECK(!inside_inner_message_loop_);
DCHECK(!print_job_->document() || print_job_->document()->IsComplete());
// WebContents is either dying or navigating elsewhere. We need to render
// all the pages in an hurry if a print job is still pending. This does the
// trick since it runs a blocking message loop:
print_job_->Stop();
}
ReleasePrintJob();
}
void PrintViewManagerBase::ReleasePrintJob() {
if (!print_job_.get())
return;
PrintingDone(printing_succeeded_);
registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_EVENT,
content::Source<PrintJob>(print_job_.get()));
print_job_->DisconnectSource();
// Don't close the worker thread.
print_job_ = NULL;
}
bool PrintViewManagerBase::RunInnerMessageLoop() {
// This value may actually be too low:
//
// - If we're looping because of printer settings initialization, the premise
// here is that some poor users have their print server away on a VPN over a
// slow connection. In this situation, the simple fact of opening the printer
// can be dead slow. On the other side, we don't want to die infinitely for a
// real network error. Give the printer 60 seconds to comply.
//
// - If we're looping because of renderer page generation, the renderer could
// be CPU bound, the page overly complex/large or the system just
// memory-bound.
static const int kPrinterSettingsTimeout = 60000;
base::OneShotTimer<base::MessageLoop> quit_timer;
quit_timer.Start(FROM_HERE,
TimeDelta::FromMilliseconds(kPrinterSettingsTimeout),
base::MessageLoop::current(), &base::MessageLoop::Quit);
inside_inner_message_loop_ = true;
// Need to enable recursive task.
{
base::MessageLoop::ScopedNestableTaskAllower allow(
base::MessageLoop::current());
base::MessageLoop::current()->Run();
}
bool success = true;
if (inside_inner_message_loop_) {
// Ok we timed out. That's sad.
inside_inner_message_loop_ = false;
success = false;
}
return success;
}
bool PrintViewManagerBase::OpportunisticallyCreatePrintJob(int cookie) {
if (print_job_.get())
return true;
if (!cookie) {
// Out of sync. It may happens since we are completely asynchronous. Old
// spurious message can happen if one of the processes is overloaded.
return false;
}
// The job was initiated by a script. Time to get the corresponding worker
// thread.
scoped_refptr<PrinterQuery> queued_query = queue_->PopPrinterQuery(cookie);
if (!queued_query) {
NOTREACHED();
return false;
}
if (!CreateNewPrintJob(queued_query)) {
// Don't kill anything.
return false;
}
// Settings are already loaded. Go ahead. This will set
// print_job_->is_job_pending() to true.
print_job_->StartPrinting();
return true;
}
bool PrintViewManagerBase::PrintNowInternal(IPC::Message* message) {
// Don't print / print preview interstitials.
if (web_contents()->ShowingInterstitialPage()) {
delete message;
return false;
}
return Send(message);
}
void PrintViewManagerBase::ReleasePrinterQuery() {
if (!cookie_)
return;
int cookie = cookie_;
cookie_ = 0;
queue_->SetDestination(NULL);
printing::PrintJobManager* print_job_manager =
g_browser_process->print_job_manager();
// May be NULL in tests.
if (!print_job_manager)
return;
scoped_refptr<printing::PrinterQuery> printer_query;
printer_query = queue_->PopPrinterQuery(cookie);
if (!printer_query)
return;
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&PrinterQuery::StopWorker, printer_query.get()));
}
} // namespace printing

View File

@ -0,0 +1,166 @@
// Copyright 2013 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 CEF_LIBCEF_BROWSER_PRINTING_PRINT_VIEW_MANAGER_BASE_H_
#define CEF_LIBCEF_BROWSER_PRINTING_PRINT_VIEW_MANAGER_BASE_H_
#include "base/memory/ref_counted.h"
#include "base/prefs/pref_member.h"
#include "base/strings/string16.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
#include "printing/printed_pages_source.h"
struct PrintHostMsg_DidPrintPage_Params;
namespace content {
class RenderViewHost;
}
namespace printing {
class JobEventDetails;
class PrintJob;
class PrintJobWorkerOwner;
class PrintQueriesQueue;
// Base class for managing the print commands for a WebContents.
class PrintViewManagerBase : public content::NotificationObserver,
public PrintedPagesSource,
public content::WebContentsObserver {
public:
virtual ~PrintViewManagerBase();
// Prints the current document immediately. Since the rendering is
// asynchronous, the actual printing will not be completed on the return of
// this function. Returns false if printing is impossible at the moment.
virtual bool PrintNow();
// Whether to block scripted printing for our tab or not.
void UpdateScriptedPrintingBlocked();
// PrintedPagesSource implementation.
virtual string16 RenderSourceName() OVERRIDE;
protected:
explicit PrintViewManagerBase(content::WebContents* web_contents);
// Helper method for Print*Now().
bool PrintNowInternal(IPC::Message* message);
// Terminates or cancels the print job if one was pending.
virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
// content::WebContentsObserver implementation.
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
// IPC Message handlers.
virtual void OnPrintingFailed(int cookie);
private:
// content::NotificationObserver implementation.
virtual void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE;
// content::WebContentsObserver implementation.
virtual void DidStartLoading(
content::RenderViewHost* render_view_host) OVERRIDE;
// Cancels the print job.
virtual void NavigationStopped() OVERRIDE;
// IPC Message handlers.
void OnDidGetPrintedPagesCount(int cookie, int number_pages);
void OnDidGetDocumentCookie(int cookie);
void OnDidPrintPage(const PrintHostMsg_DidPrintPage_Params& params);
// Processes a NOTIFY_PRINT_JOB_EVENT notification.
void OnNotifyPrintJobEvent(const JobEventDetails& event_details);
// Requests the RenderView to render all the missing pages for the print job.
// No-op if no print job is pending. Returns true if at least one page has
// been requested to the renderer.
bool RenderAllMissingPagesNow();
// Quits the current message loop if these conditions hold true: a document is
// loaded and is complete and waiting_for_pages_to_be_rendered_ is true. This
// function is called in DidPrintPage() or on ALL_PAGES_REQUESTED
// notification. The inner message loop is created was created by
// RenderAllMissingPagesNow().
void ShouldQuitFromInnerMessageLoop();
// Creates a new empty print job. It has no settings loaded. If there is
// currently a print job, safely disconnect from it. Returns false if it is
// impossible to safely disconnect from the current print job or it is
// impossible to create a new print job.
bool CreateNewPrintJob(PrintJobWorkerOwner* job);
// Makes sure the current print_job_ has all its data before continuing, and
// disconnect from it.
void DisconnectFromCurrentPrintJob();
// Notify that the printing is done.
void PrintingDone(bool success);
// Terminates the print job. No-op if no print job has been created. If
// |cancel| is true, cancel it instead of waiting for the job to finish. Will
// call ReleasePrintJob().
void TerminatePrintJob(bool cancel);
// Releases print_job_. Correctly deregisters from notifications. No-op if
// no print job has been created.
void ReleasePrintJob();
// Runs an inner message loop. It will set inside_inner_message_loop_ to true
// while the blocking inner message loop is running. This is useful in cases
// where the RenderView is about to be destroyed while a printing job isn't
// finished.
bool RunInnerMessageLoop();
// In the case of Scripted Printing, where the renderer is controlling the
// control flow, print_job_ is initialized whenever possible. No-op is
// print_job_ is initialized.
bool OpportunisticallyCreatePrintJob(int cookie);
// Release the PrinterQuery associated with our |cookie_|.
void ReleasePrinterQuery();
content::NotificationRegistrar registrar_;
// Manages the low-level talk to the printer.
scoped_refptr<PrintJob> print_job_;
// Number of pages to print in the print job.
int number_pages_;
// Indication of success of the print job.
bool printing_succeeded_;
// Running an inner message loop inside RenderAllMissingPagesNow(). This means
// we are _blocking_ until all the necessary pages have been rendered or the
// print settings are being loaded.
bool inside_inner_message_loop_;
#if defined(OS_POSIX) && !defined(OS_MACOSX)
// Set to true when OnDidPrintPage() should be expecting the first page.
bool expecting_first_page_;
#endif
// The document cookie of the current PrinterQuery.
int cookie_;
// Whether printing is enabled.
BooleanPrefMember printing_enabled_;
scoped_refptr<printing::PrintQueriesQueue> queue_;
DISALLOW_COPY_AND_ASSIGN(PrintViewManagerBase);
};
} // namespace printing
#endif // CEF_LIBCEF_BROWSER_PRINTING_PRINT_VIEW_MANAGER_BASE_H_

View File

@ -0,0 +1,446 @@
// 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 "libcef/browser/printing/printing_message_filter.h"
#include <string>
#include "base/bind.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/printing/printer_query.h"
#include "chrome/browser/printing/print_job_manager.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_contents_view.h"
#if defined(OS_CHROMEOS)
#include <fcntl.h>
#include <map>
#include "base/file_util.h"
#include "base/lazy_instance.h"
#include "chrome/browser/printing/print_dialog_cloud.h"
#endif
#if defined(OS_ANDROID)
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/printing/print_view_manager_basic.h"
#include "printing/printing_context_android.h"
#endif
using content::BrowserThread;
namespace {
#if defined(OS_CHROMEOS)
typedef std::map<int, base::FilePath> SequenceToPathMap;
struct PrintingSequencePathMap {
SequenceToPathMap map;
int sequence;
};
// No locking, only access on the FILE thread.
static base::LazyInstance<PrintingSequencePathMap>
g_printing_file_descriptor_map = LAZY_INSTANCE_INITIALIZER;
#endif
void RenderParamsFromPrintSettings(const printing::PrintSettings& settings,
PrintMsg_Print_Params* params) {
params->page_size = settings.page_setup_device_units().physical_size();
params->content_size.SetSize(
settings.page_setup_device_units().content_area().width(),
settings.page_setup_device_units().content_area().height());
params->printable_area.SetRect(
settings.page_setup_device_units().printable_area().x(),
settings.page_setup_device_units().printable_area().y(),
settings.page_setup_device_units().printable_area().width(),
settings.page_setup_device_units().printable_area().height());
params->margin_top = settings.page_setup_device_units().content_area().y();
params->margin_left = settings.page_setup_device_units().content_area().x();
params->dpi = settings.dpi();
// Currently hardcoded at 1.25. See PrintSettings' constructor.
params->min_shrink = settings.min_shrink;
// Currently hardcoded at 2.0. See PrintSettings' constructor.
params->max_shrink = settings.max_shrink;
// Currently hardcoded at 72dpi. See PrintSettings' constructor.
params->desired_dpi = settings.desired_dpi;
// Always use an invalid cookie.
params->document_cookie = 0;
params->selection_only = settings.selection_only;
params->supports_alpha_blend = settings.supports_alpha_blend();
params->should_print_backgrounds = settings.should_print_backgrounds;
params->display_header_footer = settings.display_header_footer;
params->date = settings.date;
params->title = settings.title;
params->url = settings.url;
}
} // namespace
PrintingMessageFilter::PrintingMessageFilter(int render_process_id)
: render_process_id_(render_process_id),
queue_(g_browser_process->print_job_manager()->queue()) {
DCHECK(queue_);
}
PrintingMessageFilter::~PrintingMessageFilter() {
}
void PrintingMessageFilter::OverrideThreadForMessage(
const IPC::Message& message, BrowserThread::ID* thread) {
#if defined(OS_CHROMEOS)
if (message.type() == PrintHostMsg_AllocateTempFileForPrinting::ID ||
message.type() == PrintHostMsg_TempFileForPrintingWritten::ID) {
*thread = BrowserThread::FILE;
}
#elif defined(OS_ANDROID)
if (message.type() == PrintHostMsg_AllocateTempFileForPrinting::ID ||
message.type() == PrintHostMsg_TempFileForPrintingWritten::ID) {
*thread = BrowserThread::UI;
}
#endif
}
bool PrintingMessageFilter::OnMessageReceived(const IPC::Message& message,
bool* message_was_ok) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP_EX(PrintingMessageFilter, message, *message_was_ok)
#if defined(OS_WIN)
IPC_MESSAGE_HANDLER(PrintHostMsg_DuplicateSection, OnDuplicateSection)
#endif
#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
IPC_MESSAGE_HANDLER(PrintHostMsg_AllocateTempFileForPrinting,
OnAllocateTempFileForPrinting)
IPC_MESSAGE_HANDLER(PrintHostMsg_TempFileForPrintingWritten,
OnTempFileForPrintingWritten)
#endif
IPC_MESSAGE_HANDLER(PrintHostMsg_IsPrintingEnabled, OnIsPrintingEnabled)
IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_GetDefaultPrintSettings,
OnGetDefaultPrintSettings)
IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_ScriptedPrint, OnScriptedPrint)
IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_UpdatePrintSettings,
OnUpdatePrintSettings)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
#if defined(OS_WIN)
void PrintingMessageFilter::OnDuplicateSection(
base::SharedMemoryHandle renderer_handle,
base::SharedMemoryHandle* browser_handle) {
// Duplicate the handle in this process right now so the memory is kept alive
// (even if it is not mapped)
base::SharedMemory shared_buf(renderer_handle, true, PeerHandle());
shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), browser_handle);
}
#endif
#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
void PrintingMessageFilter::OnAllocateTempFileForPrinting(
int render_view_id,
base::FileDescriptor* temp_file_fd,
int* sequence_number) {
#if defined(OS_CHROMEOS)
// TODO(thestig): Use |render_view_id| for Chrome OS.
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
temp_file_fd->fd = *sequence_number = -1;
temp_file_fd->auto_close = false;
SequenceToPathMap* map = &g_printing_file_descriptor_map.Get().map;
*sequence_number = g_printing_file_descriptor_map.Get().sequence++;
base::FilePath path;
if (file_util::CreateTemporaryFile(&path)) {
int fd = open(path.value().c_str(), O_WRONLY);
if (fd >= 0) {
SequenceToPathMap::iterator it = map->find(*sequence_number);
if (it != map->end()) {
NOTREACHED() << "Sequence number already in use. seq=" <<
*sequence_number;
} else {
(*map)[*sequence_number] = path;
temp_file_fd->fd = fd;
temp_file_fd->auto_close = true;
}
}
}
#elif defined(OS_ANDROID)
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
if (!wc)
return;
printing::PrintViewManagerBasic* print_view_manager =
printing::PrintViewManagerBasic::FromWebContents(wc);
// The file descriptor is originally created in & passed from the Android
// side, and it will handle the closing.
const base::FileDescriptor& file_descriptor =
print_view_manager->file_descriptor();
temp_file_fd->fd = file_descriptor.fd;
temp_file_fd->auto_close = false;
#endif
}
void PrintingMessageFilter::OnTempFileForPrintingWritten(int render_view_id,
int sequence_number) {
#if defined(OS_CHROMEOS)
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
SequenceToPathMap* map = &g_printing_file_descriptor_map.Get().map;
SequenceToPathMap::iterator it = map->find(sequence_number);
if (it == map->end()) {
NOTREACHED() << "Got a sequence that we didn't pass to the "
"renderer: " << sequence_number;
return;
}
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&PrintingMessageFilter::CreatePrintDialogForFile,
this, render_view_id, it->second));
// Erase the entry in the map.
map->erase(it);
#elif defined(OS_ANDROID)
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
if (!wc)
return;
printing::PrintViewManagerBasic* print_view_manager =
printing::PrintViewManagerBasic::FromWebContents(wc);
const base::FileDescriptor& file_descriptor =
print_view_manager->file_descriptor();
printing::PrintingContextAndroid::PdfWritingDone(file_descriptor.fd, true);
// Invalidate the file descriptor so it doesn't accidentally get reused.
print_view_manager->set_file_descriptor(base::FileDescriptor(-1, false));
#endif
}
#endif // defined(OS_CHROMEOS) || defined(OS_ANDROID)
#if defined(OS_CHROMEOS)
void PrintingMessageFilter::CreatePrintDialogForFile(
int render_view_id,
const base::FilePath& path) {
content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
if (!wc)
return;
print_dialog_cloud::CreatePrintDialogForFile(
wc->GetBrowserContext(),
wc->GetView()->GetTopLevelNativeWindow(),
path,
wc->GetTitle(),
string16(),
std::string("application/pdf"),
false);
}
#endif // defined(OS_CHROMEOS)
content::WebContents* PrintingMessageFilter::GetWebContentsForRenderView(
int render_view_id) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
content::RenderViewHost* view = content::RenderViewHost::FromID(
render_process_id_, render_view_id);
return view ? content::WebContents::FromRenderViewHost(view) : NULL;
}
struct PrintingMessageFilter::GetPrintSettingsForRenderViewParams {
printing::PrinterQuery::GetSettingsAskParam ask_user_for_settings;
int expected_page_count;
bool has_selection;
printing::MarginType margin_type;
};
void PrintingMessageFilter::GetPrintSettingsForRenderView(
int render_view_id,
GetPrintSettingsForRenderViewParams params,
const base::Closure& callback,
scoped_refptr<printing::PrinterQuery> printer_query) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
if (wc) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&printing::PrinterQuery::GetSettings, printer_query,
params.ask_user_for_settings, wc->GetView()->GetNativeView(),
params.expected_page_count, params.has_selection,
params.margin_type, callback));
} else {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&PrintingMessageFilter::OnGetPrintSettingsFailed, this,
callback, printer_query));
}
}
void PrintingMessageFilter::OnGetPrintSettingsFailed(
const base::Closure& callback,
scoped_refptr<printing::PrinterQuery> printer_query) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
printer_query->GetSettingsDone(printing::PrintSettings(),
printing::PrintingContext::FAILED);
callback.Run();
}
void PrintingMessageFilter::OnIsPrintingEnabled(bool* is_enabled) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
*is_enabled = true;
}
void PrintingMessageFilter::OnGetDefaultPrintSettings(IPC::Message* reply_msg) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
scoped_refptr<printing::PrinterQuery> printer_query;
printer_query = queue_->PopPrinterQuery(0);
if (!printer_query)
printer_query = queue_->CreatePrinterQuery();
// Loads default settings. This is asynchronous, only the IPC message sender
// will hang until the settings are retrieved.
GetPrintSettingsForRenderViewParams params;
params.ask_user_for_settings = printing::PrinterQuery::DEFAULTS;
params.expected_page_count = 0;
params.has_selection = false;
params.margin_type = printing::DEFAULT_MARGINS;
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&PrintingMessageFilter::GetPrintSettingsForRenderView, this,
reply_msg->routing_id(), params,
base::Bind(&PrintingMessageFilter::OnGetDefaultPrintSettingsReply,
this, printer_query, reply_msg),
printer_query));
}
void PrintingMessageFilter::OnGetDefaultPrintSettingsReply(
scoped_refptr<printing::PrinterQuery> printer_query,
IPC::Message* reply_msg) {
PrintMsg_Print_Params params;
if (!printer_query.get() ||
printer_query->last_status() != printing::PrintingContext::OK) {
params.Reset();
} else {
RenderParamsFromPrintSettings(printer_query->settings(), &params);
params.document_cookie = printer_query->cookie();
}
PrintHostMsg_GetDefaultPrintSettings::WriteReplyParams(reply_msg, params);
Send(reply_msg);
// If printing was enabled.
if (printer_query.get()) {
// If user hasn't cancelled.
if (printer_query->cookie() && printer_query->settings().dpi()) {
queue_->QueuePrinterQuery(printer_query.get());
} else {
printer_query->StopWorker();
}
}
}
void PrintingMessageFilter::OnScriptedPrint(
const PrintHostMsg_ScriptedPrint_Params& params,
IPC::Message* reply_msg) {
scoped_refptr<printing::PrinterQuery> printer_query =
queue_->PopPrinterQuery(params.cookie);
if (!printer_query)
printer_query = queue_->CreatePrinterQuery();
GetPrintSettingsForRenderViewParams settings_params;
settings_params.ask_user_for_settings = printing::PrinterQuery::ASK_USER;
settings_params.expected_page_count = params.expected_pages_count;
settings_params.has_selection = params.has_selection;
settings_params.margin_type = params.margin_type;
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&PrintingMessageFilter::GetPrintSettingsForRenderView, this,
reply_msg->routing_id(), settings_params,
base::Bind(&PrintingMessageFilter::OnScriptedPrintReply, this,
printer_query, reply_msg),
printer_query));
}
void PrintingMessageFilter::OnScriptedPrintReply(
scoped_refptr<printing::PrinterQuery> printer_query,
IPC::Message* reply_msg) {
PrintMsg_PrintPages_Params params;
#if defined(OS_ANDROID)
// We need to save the routing ID here because Send method below deletes the
// |reply_msg| before we can get the routing ID for the Android code.
int routing_id = reply_msg->routing_id();
#endif
if (printer_query->last_status() != printing::PrintingContext::OK ||
!printer_query->settings().dpi()) {
params.Reset();
} else {
RenderParamsFromPrintSettings(printer_query->settings(), &params.params);
params.params.document_cookie = printer_query->cookie();
params.pages =
printing::PageRange::GetPages(printer_query->settings().ranges);
}
PrintHostMsg_ScriptedPrint::WriteReplyParams(reply_msg, params);
Send(reply_msg);
if (params.params.dpi && params.params.document_cookie) {
#if defined(OS_ANDROID)
int file_descriptor;
const string16& device_name = printer_query->settings().device_name();
if (base::StringToInt(device_name, &file_descriptor)) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&PrintingMessageFilter::UpdateFileDescriptor, this,
routing_id, file_descriptor));
}
#endif
queue_->QueuePrinterQuery(printer_query.get());
} else {
printer_query->StopWorker();
}
}
#if defined(OS_ANDROID)
void PrintingMessageFilter::UpdateFileDescriptor(int render_view_id, int fd) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
if (!wc)
return;
printing::PrintViewManagerBasic* print_view_manager =
printing::PrintViewManagerBasic::FromWebContents(wc);
print_view_manager->set_file_descriptor(base::FileDescriptor(fd, false));
}
#endif
void PrintingMessageFilter::OnUpdatePrintSettings(
int document_cookie, const DictionaryValue& job_settings,
IPC::Message* reply_msg) {
scoped_refptr<printing::PrinterQuery> printer_query;
printer_query = queue_->PopPrinterQuery(document_cookie);
if (!printer_query)
printer_query = queue_->CreatePrinterQuery();
printer_query->SetSettings(
job_settings,
base::Bind(&PrintingMessageFilter::OnUpdatePrintSettingsReply, this,
printer_query, reply_msg));
}
void PrintingMessageFilter::OnUpdatePrintSettingsReply(
scoped_refptr<printing::PrinterQuery> printer_query,
IPC::Message* reply_msg) {
PrintMsg_PrintPages_Params params;
if (!printer_query.get() ||
printer_query->last_status() != printing::PrintingContext::OK) {
params.Reset();
} else {
RenderParamsFromPrintSettings(printer_query->settings(), &params.params);
params.params.document_cookie = printer_query->cookie();
params.pages =
printing::PageRange::GetPages(printer_query->settings().ranges);
}
PrintHostMsg_UpdatePrintSettings::WriteReplyParams(reply_msg, params);
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();
}
}
}

View File

@ -0,0 +1,132 @@
// 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 CEF_LIBCEF_BROWSER_PRINTING_PRINTING_MESSAGE_FILTER_H_
#define CEF_LIBCEF_BROWSER_PRINTING_PRINTING_MESSAGE_FILTER_H_
#include <string>
#include "base/compiler_specific.h"
#include "content/public/browser/browser_message_filter.h"
#if defined(OS_WIN)
#include "base/memory/shared_memory.h"
#endif
struct PrintHostMsg_ScriptedPrint_Params;
namespace base {
class DictionaryValue;
class FilePath;
}
namespace content {
class WebContents;
}
namespace printing {
class PrinterQuery;
class PrintJobManager;
class PrintQueriesQueue;
}
// This class filters out incoming printing related IPC messages for the
// renderer process on the IPC thread.
class PrintingMessageFilter : public content::BrowserMessageFilter {
public:
explicit PrintingMessageFilter(int render_process_id);
// content::BrowserMessageFilter methods.
virtual void OverrideThreadForMessage(
const IPC::Message& message,
content::BrowserThread::ID* thread) OVERRIDE;
virtual bool OnMessageReceived(const IPC::Message& message,
bool* message_was_ok) OVERRIDE;
private:
virtual ~PrintingMessageFilter();
#if defined(OS_WIN)
// Used to pass resulting EMF from renderer to browser in printing.
void OnDuplicateSection(base::SharedMemoryHandle renderer_handle,
base::SharedMemoryHandle* browser_handle);
#endif
#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
// Used to ask the browser allocate a temporary file for the renderer
// to fill in resulting PDF in renderer.
void OnAllocateTempFileForPrinting(int render_view_id,
base::FileDescriptor* temp_file_fd,
int* sequence_number);
void OnTempFileForPrintingWritten(int render_view_id, int sequence_number);
#endif
#if defined(OS_CHROMEOS)
void CreatePrintDialogForFile(int render_view_id, const base::FilePath& path);
#endif
#if defined(OS_ANDROID)
// Updates the file descriptor for the PrintViewManagerBasic of a given
// render_view_id.
void UpdateFileDescriptor(int render_view_id, int fd);
#endif
// Given a render_view_id get the corresponding WebContents.
// Must be called on the UI thread.
content::WebContents* GetWebContentsForRenderView(int render_view_id);
// GetPrintSettingsForRenderView must be called via PostTask and
// base::Bind. Collapse the settings-specific params into a
// struct to avoid running into issues with too many params
// to base::Bind.
struct GetPrintSettingsForRenderViewParams;
// Retrieve print settings. Uses |render_view_id| to get a parent
// for any UI created if needed.
void GetPrintSettingsForRenderView(
int render_view_id,
GetPrintSettingsForRenderViewParams params,
const base::Closure& callback,
scoped_refptr<printing::PrinterQuery> printer_query);
void OnGetPrintSettingsFailed(
const base::Closure& callback,
scoped_refptr<printing::PrinterQuery> printer_query);
// Checks if printing is enabled.
void OnIsPrintingEnabled(bool* is_enabled);
// Get the default print setting.
void OnGetDefaultPrintSettings(IPC::Message* reply_msg);
void OnGetDefaultPrintSettingsReply(
scoped_refptr<printing::PrinterQuery> printer_query,
IPC::Message* reply_msg);
// The renderer host have to show to the user the print dialog and returns
// the selected print settings. The task is handled by the print worker
// thread and the UI thread. The reply occurs on the IO thread.
void OnScriptedPrint(const PrintHostMsg_ScriptedPrint_Params& params,
IPC::Message* reply_msg);
void OnScriptedPrintReply(
scoped_refptr<printing::PrinterQuery> printer_query,
IPC::Message* reply_msg);
// Modify the current print settings based on |job_settings|. The task is
// handled by the print worker thread and the UI thread. The reply occurs on
// the IO thread.
void OnUpdatePrintSettings(int document_cookie,
const base::DictionaryValue& job_settings,
IPC::Message* reply_msg);
void OnUpdatePrintSettingsReply(
scoped_refptr<printing::PrinterQuery> printer_query,
IPC::Message* reply_msg);
const int render_process_id_;
scoped_refptr<printing::PrintQueriesQueue> queue_;
DISALLOW_COPY_AND_ASSIGN(PrintingMessageFilter);
};
#endif // CEF_LIBCEF_BROWSER_PRINTING_PRINTING_MESSAGE_FILTER_H_

View File

@ -218,3 +218,6 @@ struct ParamTraits<scoped_refptr<net::UploadData> > {
} // namespace IPC
#endif // CEF_LIBCEF_COMMON_CEF_MESSAGES_H_
#include "chrome/common/prerender_messages.h"
#include "chrome/common/print_messages.h"

View File

@ -33,6 +33,7 @@ MSVC_POP_WARNING();
#include "base/path_service.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/renderer/loadtimes_extension_bindings.h"
#include "chrome/renderer/printing/print_web_view_helper.h"
#include "content/child/child_thread.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_process_host.h"
@ -443,6 +444,7 @@ void CefContentRendererClient::RenderViewCreated(
browsers_.insert(std::make_pair(render_view, browser));
new CefPrerendererClient(render_view);
new printing::PrintWebViewHelper(render_view);
// Notify the render process handler.
CefRefPtr<CefApp> application = CefContentClient::Get()->application();

View File

@ -15,6 +15,7 @@
<include name="IDR_CEF_CREDITS_SWIFTSHADER_JPG" file="..\..\..\chrome\browser\resources\swiftshader.jpg" type="BINDATA" />
<include name="IDR_CEF_LICENSE_TXT" file="..\..\LICENSE.txt" type="BINDATA" />
<include name="IDR_CEF_VERSION_HTML" file="about_version.html" type="BINDATA" />
<include name="IDR_PRINT_PREVIEW_PAGE" file="print_preview_page_stub.html" type="BINDATA" />
</includes>
</release>
</grit>

View File

@ -263,6 +263,20 @@ need to be translated for each locale.-->
<message name="IDS_APP_VIDEO_FILES" desc="The text label for the Video Files filter in file open/save dialogs.">
Video Files
</message>
<!-- Print -->
<message name="IDS_DEFAULT_PRINT_DOCUMENT_TITLE" desc="Default title for a print document">
Untitled Document
</message>
<message name="IDS_PRINT_SPOOL_FAILED_TITLE_TEXT" desc="Title of a message box when printing fails because of printer issues.">
Print Failed
</message>
<message name="IDS_PRINT_SPOOL_FAILED_ERROR_TEXT" desc="Text in a messagebox when printing fails because of printer issues.">
Something went wrong when trying to print. Please check your printer and try again.
</message>
<message name="IDS_PRINT_PREVIEW_INVALID_PRINTER_SETTINGS" desc="Message to display when selected printer is not reachable or its settings are invalid.">
The selected printer is not available or not installed correctly. Check your printer or try selecting another printer.
</message>
</messages>
</release>
</grit>

View File

@ -0,0 +1,2 @@
#include <grit/cef_resources.h>
#include <grit/cef_strings.h>

View File

@ -0,0 +1,2 @@
#include <grit/cef_resources.h>
#include <grit/cef_strings.h>

View File

@ -0,0 +1 @@
<html></html>

View File

@ -302,6 +302,17 @@ void CEF_CALLBACK browser_host_start_download(struct _cef_browser_host_t* self,
CefString(url));
}
void CEF_CALLBACK browser_host_print(struct _cef_browser_host_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Execute
CefBrowserHostCppToC::Get(self)->Print();
}
void CEF_CALLBACK browser_host_set_mouse_cursor_change_disabled(
struct _cef_browser_host_t* self, int disabled) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
@ -586,6 +597,7 @@ CefBrowserHostCppToC::CefBrowserHostCppToC(CefBrowserHost* cls)
struct_.struct_.set_zoom_level = browser_host_set_zoom_level;
struct_.struct_.run_file_dialog = browser_host_run_file_dialog;
struct_.struct_.start_download = browser_host_start_download;
struct_.struct_.print = browser_host_print;
struct_.struct_.set_mouse_cursor_change_disabled =
browser_host_set_mouse_cursor_change_disabled;
struct_.struct_.is_mouse_cursor_change_disabled =

View File

@ -250,6 +250,16 @@ void CefBrowserHostCToCpp::StartDownload(const CefString& url) {
url.GetStruct());
}
void CefBrowserHostCToCpp::Print() {
if (CEF_MEMBER_MISSING(struct_, print))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
struct_->print(struct_);
}
void CefBrowserHostCToCpp::SetMouseCursorChangeDisabled(bool disabled) {
if (CEF_MEMBER_MISSING(struct_, set_mouse_cursor_change_disabled))
return;

View File

@ -53,6 +53,7 @@ class CefBrowserHostCToCpp
const std::vector<CefString>& accept_types,
CefRefPtr<CefRunFileDialogCallback> callback) OVERRIDE;
virtual void StartDownload(const CefString& url) OVERRIDE;
virtual void Print() OVERRIDE;
virtual void SetMouseCursorChangeDisabled(bool disabled) OVERRIDE;
virtual bool IsMouseCursorChangeDisabled() OVERRIDE;
virtual bool IsWindowRenderingDisabled() OVERRIDE;

View File

@ -78,6 +78,7 @@ BEGIN
MENUITEM "Zoom Reset", ID_TESTS_ZOOM_RESET
MENUITEM "Begin Tracing", ID_TESTS_TRACING_BEGIN
MENUITEM "End Tracing", ID_TESTS_TRACING_END
MENUITEM "Print", ID_TESTS_PRINT
MENUITEM "Other Tests", ID_TESTS_OTHER_TESTS
END
END

View File

@ -149,6 +149,14 @@ gboolean EndTracingActivated(GtkWidget* widget) {
return FALSE; // Don't stop this message.
}
// Callback for Tests > Print menu item.
gboolean PrintActivated(GtkWidget* widget) {
if (g_handler.get())
g_handler->GetBrowser()->GetHost()->Print();
return FALSE; // Don't stop this message.
}
// Callback for Tests > Other Tests... menu item.
gboolean OtherTestsActivated(GtkWidget* widget) {
if (g_handler.get() && g_handler->GetBrowserId())
@ -232,6 +240,8 @@ GtkWidget* CreateMenuBar() {
G_CALLBACK(BeginTracingActivated));
AddMenuEntry(debug_menu, "End Tracing",
G_CALLBACK(EndTracingActivated));
AddMenuEntry(debug_menu, "Print",
G_CALLBACK(PrintActivated));
AddMenuEntry(debug_menu, "Other Tests",
G_CALLBACK(OtherTestsActivated));
return menu_bar;

View File

@ -217,6 +217,7 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) {
- (IBAction)testZoomReset:(id)sender;
- (IBAction)testBeginTracing:(id)sender;
- (IBAction)testEndTracing:(id)sender;
- (IBAction)testPrint:(id)sender;
- (IBAction)testOtherTests:(id)sender;
@end
@ -266,6 +267,9 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) {
[testMenu addItemWithTitle:@"End Tracing"
action:@selector(testEndTracing:)
keyEquivalent:@""];
[testMenu addItemWithTitle:@"Print"
action:@selector(testPrint:)
keyEquivalent:@""];
[testMenu addItemWithTitle:@"Other Tests"
action:@selector(testOtherTests:)
keyEquivalent:@""];
@ -428,6 +432,11 @@ NSButton* MakeButton(NSRect* rect, NSString* title, NSView* parent) {
g_handler->EndTracing();
}
- (IBAction)testPrint:(id)sender {
if (g_handler.get() && g_handler->GetBrowserId())
g_handler->GetBrowser()->GetHost()->Print();
}
- (IBAction)testOtherTests:(id)sender {
if (g_handler.get() && g_handler->GetBrowserId())
RunOtherTests(g_handler->GetBrowser());

View File

@ -430,6 +430,10 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam,
case ID_TESTS_TRACING_END:
g_handler->EndTracing();
return 0;
case ID_TESTS_PRINT:
if(browser.get())
browser->GetHost()->Print();
return 0;
case ID_TESTS_OTHER_TESTS:
if (browser.get())
RunOtherTests(browser);

View File

@ -27,6 +27,7 @@
<li><a href="http://webglsamples.googlecode.com/hg/field/field.html">WebGL</a></li>
<li><a href="http://apprtc.appspot.com/">WebRTC</a> - requires "enable-media-stream" flag</li>
<li><a href="http://tests/xmlhttprequest">XMLHttpRequest</a></li>
<li><a href="javascript:window.print();">Print this page with &quot;javascript:window.print();&quot;</a></li>
</ul>
</body>
</html>

View File

@ -31,12 +31,13 @@
#define ID_TESTS_OTHER_TESTS 32702
#define ID_TESTS_PLUGIN_INFO 32703
#define ID_TESTS_POPUP 32704
#define ID_TESTS_REQUEST 32705
#define ID_TESTS_TRACING_BEGIN 32706
#define ID_TESTS_TRACING_END 32707
#define ID_TESTS_ZOOM_IN 32708
#define ID_TESTS_ZOOM_OUT 32709
#define ID_TESTS_ZOOM_RESET 32710
#define ID_TESTS_PRINT 32705
#define ID_TESTS_REQUEST 32706
#define ID_TESTS_TRACING_BEGIN 32707
#define ID_TESTS_TRACING_END 32708
#define ID_TESTS_ZOOM_IN 32709
#define ID_TESTS_ZOOM_OUT 32710
#define ID_TESTS_ZOOM_RESET 32711
#define IDC_STATIC -1
#define IDS_BINDING 1000
#define IDS_DIALOGS 1001

View File

@ -368,7 +368,7 @@
# gtk requires gmodule, but it does not list it as a dependency
# in some misconfigured systems.
# gtkglext is required by the cefclient OSR example.
'gtk_packages': 'gmodule-2.0 gtk+-2.0 gthread-2.0 gtkglext-1.0',
'gtk_packages': 'gmodule-2.0 gtk+-2.0 gthread-2.0 gtkglext-1.0 gtk+-unix-print-2.0',
},
'direct_dependent_settings': {
'cflags': [