Merge pull request #599 from atom/printing

Add support for printing
This commit is contained in:
Cheng Zhao 2014-08-22 17:48:36 +08:00
commit 0b24883649
48 changed files with 5988 additions and 34 deletions

View file

@ -167,7 +167,6 @@
'atom/browser/window_list.cc',
'atom/browser/window_list.h',
'atom/browser/window_list_observer.h',
'atom/common/api/api_messages.cc',
'atom/common/api/api_messages.h',
'atom/common/api/atom_api_clipboard.cc',
'atom/common/api/atom_api_crash_reporter.cc',
@ -181,6 +180,8 @@
'atom/common/api/atom_bindings.h',
'atom/common/api/object_life_monitor.cc',
'atom/common/api/object_life_monitor.h',
'atom/common/common_message_generator.cc',
'atom/common/common_message_generator.h',
'atom/common/crash_reporter/crash_reporter.cc',
'atom/common/crash_reporter/crash_reporter.h',
'atom/common/crash_reporter/crash_reporter_linux.cc',
@ -233,6 +234,9 @@
'atom/renderer/atom_render_view_observer.h',
'atom/renderer/atom_renderer_client.cc',
'atom/renderer/atom_renderer_client.h',
'chromium_src/chrome/browser/browser_process.cc',
'chromium_src/chrome/browser/browser_process.h',
'chromium_src/chrome/browser/chrome_notification_types.h',
'chromium_src/chrome/browser/extensions/global_shortcut_listener.cc',
'chromium_src/chrome/browser/extensions/global_shortcut_listener.h',
'chromium_src/chrome/browser/extensions/global_shortcut_listener_mac.mm',
@ -241,6 +245,24 @@
'chromium_src/chrome/browser/extensions/global_shortcut_listener_x11.h',
'chromium_src/chrome/browser/extensions/global_shortcut_listener_win.cc',
'chromium_src/chrome/browser/extensions/global_shortcut_listener_win.h',
'chromium_src/chrome/browser/printing/print_job.cc',
'chromium_src/chrome/browser/printing/print_job.h',
'chromium_src/chrome/browser/printing/print_job_manager.cc',
'chromium_src/chrome/browser/printing/print_job_manager.h',
'chromium_src/chrome/browser/printing/print_job_worker.cc',
'chromium_src/chrome/browser/printing/print_job_worker.h',
'chromium_src/chrome/browser/printing/print_job_worker_owner.h',
'chromium_src/chrome/browser/printing/print_view_manager_base.cc',
'chromium_src/chrome/browser/printing/print_view_manager_base.h',
'chromium_src/chrome/browser/printing/print_view_manager_basic.cc',
'chromium_src/chrome/browser/printing/print_view_manager_basic.h',
'chromium_src/chrome/browser/printing/print_view_manager_observer.h',
'chromium_src/chrome/browser/printing/printer_query.cc',
'chromium_src/chrome/browser/printing/printer_query.h',
'chromium_src/chrome/browser/printing/printing_message_filter.cc',
'chromium_src/chrome/browser/printing/printing_message_filter.h',
'chromium_src/chrome/browser/printing/printing_ui_web_contents_observer.cc',
'chromium_src/chrome/browser/printing/printing_ui_web_contents_observer.h',
'chromium_src/chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.cc',
'chromium_src/chrome/browser/ui/libgtk2ui/app_indicator_icon_menu.h',
'chromium_src/chrome/browser/ui/libgtk2ui/gtk2_status_icon.cc',
@ -249,6 +271,13 @@
'chromium_src/chrome/browser/ui/views/frame/global_menu_bar_registrar_x11.h',
'chromium_src/chrome/browser/ui/views/status_icons/status_tray_state_changer_win.cc',
'chromium_src/chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h',
'chromium_src/chrome/common/print_messages.cc',
'chromium_src/chrome/common/print_messages.h',
'chromium_src/chrome/renderer/printing/print_web_view_helper.cc',
'chromium_src/chrome/renderer/printing/print_web_view_helper_linux.cc',
'chromium_src/chrome/renderer/printing/print_web_view_helper_mac.mm',
'chromium_src/chrome/renderer/printing/print_web_view_helper_win.cc',
'chromium_src/chrome/renderer/printing/print_web_view_helper.h',
'<@(native_mate_files)',
],
'framework_sources': [
@ -439,6 +468,10 @@
'vendor/brightray/brightray.gyp:brightray',
'vendor/node/node.gyp:node_lib',
],
'defines': [
# This is defined in skia/skia_common.gypi.
'SK_SUPPORT_LEGACY_GETTOPDEVICE',
],
'sources': [
'<@(lib_sources)',
],

View file

@ -16,8 +16,30 @@
#include "atom/common/node_includes.h"
namespace {
struct PrintSettings {
bool silent;
bool print_backgournd;
};
} // namespace
namespace mate {
template<>
struct Converter<PrintSettings> {
static bool FromV8(v8::Isolate* isolate, v8::Handle<v8::Value> val,
PrintSettings* out) {
mate::Dictionary dict;
if (!ConvertFromV8(isolate, val, &dict))
return false;
dict.Get("silent", &(out->silent));
dict.Get("printBackground", &(out->print_backgournd));
return true;
}
};
template<>
struct Converter<gfx::Rect> {
static bool FromV8(v8::Isolate* isolate,
@ -303,6 +325,22 @@ bool Window::IsWebViewFocused() {
return window_->IsWebViewFocused();
}
void Window::SetRepresentedFilename(const std::string& filename) {
window_->SetRepresentedFilename(filename);
}
std::string Window::GetRepresentedFilename() {
return window_->GetRepresentedFilename();
}
void Window::SetDocumentEdited(bool edited) {
window_->SetDocumentEdited(edited);
}
bool Window::IsDocumentEdited() {
return window_->IsDocumentEdited();
}
void Window::CapturePage(mate::Arguments* args) {
gfx::Rect rect;
base::Callback<void(v8::Handle<v8::Value>)> callback;
@ -318,20 +356,14 @@ void Window::CapturePage(mate::Arguments* args) {
rect, base::Bind(&OnCapturePageDone, args->isolate(), callback));
}
void Window::SetRepresentedFilename(const std::string& filename) {
window_->SetRepresentedFilename(filename);
}
void Window::Print(mate::Arguments* args) {
PrintSettings settings = { false, false };;
if (args->Length() == 1 && !args->GetNext(&settings)) {
args->ThrowError();
return;
}
std::string Window::GetRepresentedFilename() {
return window_->GetRepresentedFilename();
}
void Window::SetDocumentEdited(bool edited) {
window_->SetDocumentEdited(edited);
}
bool Window::IsDocumentEdited() {
return window_->IsDocumentEdited();
window_->Print(settings.silent, settings.print_backgournd);
}
mate::Handle<WebContents> Window::GetWebContents(v8::Isolate* isolate) const {
@ -386,7 +418,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setRepresentedFilename", &Window::SetRepresentedFilename)
.SetMethod("getRepresentedFilename", &Window::GetRepresentedFilename)
.SetMethod("setDocumentEdited", &Window::SetDocumentEdited)
.SetMethod("IsDocumentEdited", &Window::IsDocumentEdited)
.SetMethod("isDocumentEdited", &Window::IsDocumentEdited)
.SetMethod("_openDevTools", &Window::OpenDevTools)
.SetMethod("closeDevTools", &Window::CloseDevTools)
.SetMethod("isDevToolsOpened", &Window::IsDevToolsOpened)
@ -395,6 +427,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
.SetMethod("blurWebView", &Window::BlurWebView)
.SetMethod("isWebViewFocused", &Window::IsWebViewFocused)
.SetMethod("capturePage", &Window::CapturePage)
.SetMethod("print", &Window::Print)
.SetMethod("_getWebContents", &Window::GetWebContents)
.SetMethod("_getDevToolsWebContents", &Window::GetDevToolsWebContents);
}

View file

@ -97,11 +97,12 @@ class Window : public mate::EventEmitter,
void FocusOnWebView();
void BlurWebView();
bool IsWebViewFocused();
void CapturePage(mate::Arguments* args);
void SetRepresentedFilename(const std::string& filename);
std::string GetRepresentedFilename();
void SetDocumentEdited(bool edited);
bool IsDocumentEdited();
void CapturePage(mate::Arguments* args);
void Print(mate::Arguments* args);
// APIs for WebContents.
mate::Handle<WebContents> GetWebContents(v8::Isolate* isolate) const;

View file

@ -10,6 +10,7 @@
#include "atom/browser/atom_resource_dispatcher_host_delegate.h"
#include "atom/browser/native_window.h"
#include "atom/browser/window_list.h"
#include "chrome/browser/printing/printing_message_filter.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/resource_dispatcher_host.h"
@ -48,6 +49,11 @@ AtomBrowserClient::AtomBrowserClient()
AtomBrowserClient::~AtomBrowserClient() {
}
void AtomBrowserClient::RenderProcessWillLaunch(
content::RenderProcessHost* host) {
host->AddFilter(new PrintingMessageFilter(host->GetID()));
}
void AtomBrowserClient::ResourceDispatcherHostCreated() {
resource_dispatcher_delegate_.reset(new AtomResourceDispatcherHostDelegate);
content::ResourceDispatcherHost::Get()->SetDelegate(

View file

@ -20,6 +20,8 @@ class AtomBrowserClient : public brightray::BrowserClient {
protected:
// content::ContentBrowserClient:
virtual void RenderProcessWillLaunch(
content::RenderProcessHost* host) OVERRIDE;
virtual void ResourceDispatcherHostCreated() OVERRIDE;
virtual content::AccessTokenStore* CreateAccessTokenStore() OVERRIDE;
virtual void OverrideWebkitPrefs(content::RenderViewHost* render_view_host,

View file

@ -8,6 +8,7 @@
#include "atom/browser/net/atom_url_request_job_factory.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/worker_pool.h"
#include "chrome/browser/browser_process.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/common/url_constants.h"
#include "net/url_request/data_protocol_handler.h"
@ -19,7 +20,8 @@ using content::BrowserThread;
namespace atom {
AtomBrowserContext::AtomBrowserContext()
: job_factory_(new AtomURLRequestJobFactory) {
: fake_browser_process_(new BrowserProcess),
job_factory_(new AtomURLRequestJobFactory) {
}
AtomBrowserContext::~AtomBrowserContext() {

View file

@ -7,6 +7,8 @@
#include "brightray/browser/browser_context.h"
class BrowserProcess;
namespace atom {
class AtomURLRequestJobFactory;
@ -28,6 +30,9 @@ class AtomBrowserContext : public brightray::BrowserContext {
content::ProtocolHandlerScopedVector* interceptors) OVERRIDE;
private:
// A fake BrowserProcess object that used to feed the source code from chrome.
scoped_ptr<BrowserProcess> fake_browser_process_;
AtomURLRequestJobFactory* job_factory_; // Weak reference.
DISALLOW_COPY_AND_ASSIGN(AtomBrowserContext);

View file

@ -29,6 +29,7 @@
#include "base/strings/utf_string_conversions.h"
#include "brightray/browser/inspectable_web_contents.h"
#include "brightray/browser/inspectable_web_contents_view.h"
#include "chrome/browser/printing/print_view_manager_basic.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/invalidate_type.h"
#include "content/public/browser/navigation_entry.h"
@ -66,6 +67,8 @@ NativeWindow::NativeWindow(content::WebContents* web_contents,
weak_factory_(this),
inspectable_web_contents_(
brightray::InspectableWebContents::Create(web_contents)) {
printing::PrintViewManagerBasic::CreateForWebContents(web_contents);
options.Get(switches::kFrame, &has_frame_);
options.Get(switches::kEnableLargerThanScreen, &enable_larger_than_screen_);
@ -192,11 +195,16 @@ std::string NativeWindow::GetRepresentedFilename() {
void NativeWindow::SetDocumentEdited(bool edited) {
}
bool NativeWindow::IsDocumentEdited() {
return false;
}
void NativeWindow::SetMenu(ui::MenuModel* menu) {
}
bool NativeWindow::IsDocumentEdited() {
return false;
void NativeWindow::Print(bool silent, bool print_background) {
printing::PrintViewManagerBasic::FromWebContents(GetWebContents())->
PrintNow(silent, print_background);
}
bool NativeWindow::HasModalDialog() {

View file

@ -136,8 +136,8 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
virtual void SetRepresentedFilename(const std::string& filename);
virtual std::string GetRepresentedFilename();
virtual void SetDocumentEdited(bool edited);
virtual void SetMenu(ui::MenuModel* menu);
virtual bool IsDocumentEdited();
virtual void SetMenu(ui::MenuModel* menu);
virtual bool HasModalDialog();
virtual gfx::NativeWindow GetNativeWindow() = 0;
@ -156,6 +156,9 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
virtual void CapturePage(const gfx::Rect& rect,
const CapturePageCallback& callback);
// Print current page.
virtual void Print(bool silent, bool print_background);
// The same with closing a tab in a real browser.
//
// Should be called by platform code when user want to close the window.

View file

@ -1,33 +1,34 @@
// Copyright (c) 2013 GitHub, Inc. All rights reserved.
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
// Get basic type definitions.
#define IPC_MESSAGE_IMPL
#include "atom/common/api/api_messages.h"
#include "atom/common/common_message_generator.h"
// Generate constructors.
#include "ipc/struct_constructor_macros.h"
#include "atom/common/api/api_messages.h"
#include "atom/common/common_message_generator.h"
// Generate destructors.
#include "ipc/struct_destructor_macros.h"
#include "atom/common/api/api_messages.h"
#include "atom/common/common_message_generator.h"
// Generate param traits write methods.
#include "ipc/param_traits_write_macros.h"
namespace IPC {
#include "atom/common/api/api_messages.h"
#include "atom/common/common_message_generator.h"
} // namespace IPC
// Generate param traits read methods.
#include "ipc/param_traits_read_macros.h"
namespace IPC {
#include "atom/common/api/api_messages.h"
#include "atom/common/common_message_generator.h"
} // namespace IPC
// Generate param traits log methods.
#include "ipc/param_traits_log_macros.h"
namespace IPC {
#include "atom/common/api/api_messages.h"
#include "atom/common/common_message_generator.h"
} // namespace IPC

View file

@ -0,0 +1,8 @@
// Copyright (c) 2014 GitHub, Inc. All rights reserved.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
// Multiply-included file, no traditional include guard.
#include "atom/common/api/api_messages.h"
#include "chrome/common/print_messages.h"

View file

@ -11,6 +11,7 @@
#include "atom/common/options_switches.h"
#include "atom/renderer/api/atom_renderer_bindings.h"
#include "atom/renderer/atom_render_view_observer.h"
#include "chrome/renderer/printing/print_web_view_helper.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_frame_observer.h"
#include "base/command_line.h"
@ -105,6 +106,7 @@ void AtomRendererClient::RenderFrameCreated(
}
void AtomRendererClient::RenderViewCreated(content::RenderView* render_view) {
new printing::PrintWebViewHelper(render_view);
new AtomRenderViewObserver(render_view, this);
}

View file

@ -0,0 +1,28 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/browser_process.h"
#include "chrome/browser/printing/print_job_manager.h"
#include "ui/base/l10n/l10n_util.h"
BrowserProcess* g_browser_process = NULL;
BrowserProcess::BrowserProcess() {
g_browser_process = this;
print_job_manager_.reset(new printing::PrintJobManager);
}
BrowserProcess::~BrowserProcess() {
g_browser_process = NULL;
}
std::string BrowserProcess::GetApplicationLocale() {
return l10n_util::GetApplicationLocale("");
}
printing::PrintJobManager* BrowserProcess::print_job_manager() {
return print_job_manager_.get();
}

View file

@ -0,0 +1,41 @@
// 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.
// This interface is for managing the global services of the application. Each
// service is lazily created when requested the first time. The service getters
// will return NULL if the service is not available, so callers must check for
// this condition.
#ifndef CHROME_BROWSER_BROWSER_PROCESS_H_
#define CHROME_BROWSER_BROWSER_PROCESS_H_
#include <string>
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
namespace printing {
class PrintJobManager;
}
// NOT THREAD SAFE, call only from the main thread.
// These functions shouldn't return NULL unless otherwise noted.
class BrowserProcess {
public:
BrowserProcess();
~BrowserProcess();
std::string GetApplicationLocale();
printing::PrintJobManager* print_job_manager();
private:
scoped_ptr<printing::PrintJobManager> print_job_manager_;
DISALLOW_COPY_AND_ASSIGN(BrowserProcess);
};
extern BrowserProcess* g_browser_process;
#endif // CHROME_BROWSER_BROWSER_PROCESS_H_

View file

@ -0,0 +1,949 @@
// Copyright 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROME_NOTIFICATION_TYPES_H_
#define CHROME_BROWSER_CHROME_NOTIFICATION_TYPES_H_
#include "build/build_config.h"
#include "content/public/browser/notification_types.h"
namespace chrome {
enum NotificationType {
NOTIFICATION_CHROME_START = content::NOTIFICATION_CONTENT_END,
// Browser-window ----------------------------------------------------------
// This message is sent after a window has been opened. The source is a
// Source<Browser> containing the affected Browser. No details are
// expected.
NOTIFICATION_BROWSER_OPENED = NOTIFICATION_CHROME_START,
// This message is sent soon after BROWSER_OPENED, and indicates that
// the Browser's |window_| is now non-NULL. The source is a Source<Browser>
// containing the affected Browser. No details are expected.
NOTIFICATION_BROWSER_WINDOW_READY,
// This message is sent when a browser is closing. The source is a
// Source<Browser> containing the affected Browser. No details are expected.
// This is sent prior to BROWSER_CLOSED, and may be sent more than once for a
// particular browser.
NOTIFICATION_BROWSER_CLOSING,
// This message is sent after a window has been closed. The source is a
// Source<Browser> containing the affected Browser. No details are exptected.
NOTIFICATION_BROWSER_CLOSED,
// This message is sent when closing a browser has been cancelled, either by
// the user cancelling a beforeunload dialog, or IsClosingPermitted()
// disallowing closing. This notification implies that no BROWSER_CLOSING or
// BROWSER_CLOSED notification will be sent.
// The source is a Source<Browser> containing the affected browser. No details
// are expected.
NOTIFICATION_BROWSER_CLOSE_CANCELLED,
// Indicates that a top window has been closed. The source is the HWND
// that was closed, no details are expected.
NOTIFICATION_WINDOW_CLOSED,
#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_ANDROID)
// On Linux maximize can be an asynchronous operation. This notification
// indicates that the window has been maximized. The source is
// a Source<BrowserWindow> containing the BrowserWindow that was maximized.
// No details are expected.
NOTIFICATION_BROWSER_WINDOW_MAXIMIZED,
#endif
// Sent when the language (English, French...) for a page has been detected.
// The details Details<std::string> contain the ISO 639-1 language code and
// the source is Source<WebContents>.
NOTIFICATION_TAB_LANGUAGE_DETERMINED,
// Sent when a page has been translated. The source is the tab for that page
// (Source<WebContents>) and the details are the language the page was
// originally in and the language it was translated to
// (std::pair<std::string, std::string>).
NOTIFICATION_PAGE_TRANSLATED,
// The user has changed the browser theme. The source is a
// Source<ThemeService>. There are no details.
NOTIFICATION_BROWSER_THEME_CHANGED,
#if defined(USE_AURA)
// The user has changed the fling curve configuration.
// Source<GesturePrefsObserver>. There are no details.
NOTIFICATION_BROWSER_FLING_CURVE_PARAMETERS_CHANGED,
#endif // defined(USE_AURA)
// Sent when the renderer returns focus to the browser, as part of focus
// traversal. The source is the browser, there are no details.
NOTIFICATION_FOCUS_RETURNED_TO_BROWSER,
// A new tab is created from an existing tab to serve as a target of a
// navigation that is about to happen. The source will be a Source<Profile>
// corresponding to the profile in which the new tab will live. Details in
// the form of a RetargetingDetails object are provided.
NOTIFICATION_RETARGETING,
// Application-wide ----------------------------------------------------------
// This message is sent when the application is terminating (the last
// browser window has shutdown as part of an explicit user-initiated exit,
// or the user closed the last browser window on Windows/Linux and there are
// no BackgroundContents keeping the browser running). No source or details
// are passed.
NOTIFICATION_APP_TERMINATING,
#if defined(OS_MACOSX)
// This notification is sent when the app has no key window, such as when
// all windows are closed but the app is still active. No source or details
// are provided.
NOTIFICATION_NO_KEY_WINDOW,
#endif
// This is sent when the user has chosen to exit the app, but before any
// browsers have closed. This is sent if the user chooses to exit (via exit
// menu item or keyboard shortcut) or to restart the process (such as in flags
// page), not if Chrome exits by some other means (such as the user closing
// the last window). No source or details are passed.
//
// Note that receiving this notification does not necessarily mean the process
// will exit because the shutdown process can be cancelled by an unload
// handler. Use APP_TERMINATING for such needs.
NOTIFICATION_CLOSE_ALL_BROWSERS_REQUEST,
// Application-modal dialogs -----------------------------------------------
// Sent after an application-modal dialog has been shown. The source
// is the dialog.
NOTIFICATION_APP_MODAL_DIALOG_SHOWN,
// This message is sent when a new InfoBar has been added to an
// InfoBarService. The source is a Source<InfoBarService> with a pointer to
// the InfoBarService the InfoBar was added to. The details is a
// Details<InfoBar::AddedDetails>.
NOTIFICATION_TAB_CONTENTS_INFOBAR_ADDED,
// This message is sent when an InfoBar is about to be removed from an
// InfoBarService. The source is a Source<InfoBarService> with a pointer to
// the InfoBarService the InfoBar was removed from. The details is a
// Details<InfoBar::RemovedDetails>.
NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED,
// This message is sent when an InfoBar is replacing another infobar in an
// InfoBarService. The source is a Source<InfoBarService> with a pointer to
// the InfoBarService the InfoBar was removed from. The details is a
// Details<InfoBar::ReplacedDetails>.
NOTIFICATION_TAB_CONTENTS_INFOBAR_REPLACED,
// Used to fire notifications about how long various events took to
// complete. E.g., this is used to get more fine grained timings from the
// new tab page. The source is a WebContents and the details is a
// MetricEventDurationDetails.
NOTIFICATION_METRIC_EVENT_DURATION,
// This notification is sent when extensions::TabHelper::SetExtensionApp is
// invoked. The source is the extensions::TabHelper SetExtensionApp was
// invoked on.
NOTIFICATION_TAB_CONTENTS_APPLICATION_EXTENSION_CHANGED,
// Tabs --------------------------------------------------------------------
// Sent when a tab is added to a WebContentsDelegate. The source is the
// WebContentsDelegate and the details is the added WebContents.
NOTIFICATION_TAB_ADDED,
// This notification is sent after a tab has been appended to the tab_strip.
// The source is a Source<WebContents> of the tab being added. There
// are no details.
NOTIFICATION_TAB_PARENTED,
// This message is sent before a tab has been closed. The source is a
// Source<NavigationController> with a pointer to the controller for the
// closed tab. No details are expected.
//
// See also content::NOTIFICATION_WEB_CONTENTS_DESTROYED, which is sent when
// the WebContents containing the NavigationController is destroyed.
NOTIFICATION_TAB_CLOSING,
// Stuff inside the tabs ---------------------------------------------------
// This notification is sent when the result of a find-in-page search is
// available with the browser process. The source is a Source<WebContents>.
// Details encompass a FindNotificationDetail object that tells whether the
// match was found or not found.
NOTIFICATION_FIND_RESULT_AVAILABLE,
// BackgroundContents ------------------------------------------------------
// A new background contents was opened by script. The source is the parent
// profile and the details are BackgroundContentsOpenedDetails.
NOTIFICATION_BACKGROUND_CONTENTS_OPENED,
// The background contents navigated to a new location. The source is the
// parent Profile, and the details are the BackgroundContents that was
// navigated.
NOTIFICATION_BACKGROUND_CONTENTS_NAVIGATED,
// The background contents were closed by someone invoking window.close()
// or the parent application was uninstalled.
// The source is the parent profile, and the details are the
// BackgroundContents.
NOTIFICATION_BACKGROUND_CONTENTS_CLOSED,
// The background contents is being deleted. The source is the
// parent Profile, and the details are the BackgroundContents being deleted.
NOTIFICATION_BACKGROUND_CONTENTS_DELETED,
// The background contents has crashed. The source is the parent Profile,
// and the details are the BackgroundContents.
NOTIFICATION_BACKGROUND_CONTENTS_TERMINATED,
// The background contents associated with a hosted app has changed (either
// a new background contents has been created, or an existing background
// contents has closed). The source is the parent Profile, and the details
// are the BackgroundContentsService.
NOTIFICATION_BACKGROUND_CONTENTS_SERVICE_CHANGED,
// Chrome has entered/exited background mode. The source is the
// BackgroundModeManager and the details are a boolean value which is set to
// true if Chrome is now in background mode.
NOTIFICATION_BACKGROUND_MODE_CHANGED,
// This is sent when a login prompt is shown. The source is the
// Source<NavigationController> for the tab in which the prompt is shown.
// Details are a LoginNotificationDetails which provide the LoginHandler
// that should be given authentication.
NOTIFICATION_AUTH_NEEDED,
// This is sent when authentication credentials have been supplied (either
// by the user or by an automation service), but before we've actually
// received another response from the server. The source is the
// Source<NavigationController> for the tab in which the prompt was shown.
// Details are an AuthSuppliedLoginNotificationDetails which provide the
// LoginHandler that should be given authentication as well as the supplied
// username and password.
NOTIFICATION_AUTH_SUPPLIED,
// This is sent when an authentication request has been dismissed without
// supplying credentials (either by the user or by an automation service).
// The source is the Source<NavigationController> for the tab in which the
// prompt was shown. Details are a LoginNotificationDetails which provide
// the LoginHandler that should be cancelled.
NOTIFICATION_AUTH_CANCELLED,
// History -----------------------------------------------------------------
// Sent when a history service has finished loading. The source is the
// profile that the history service belongs to, and the details is the
// HistoryService.
NOTIFICATION_HISTORY_LOADED,
// Sent when a URL has been added or modified. This is used by the in-memory
// URL database and the InMemoryURLIndex (both used by autocomplete) to track
// changes to the main history system.
//
// The source is the profile owning the history service that changed, and
// the details is history::URLsModifiedDetails that lists the modified or
// added URLs.
NOTIFICATION_HISTORY_URLS_MODIFIED,
// Sent when the user visits a URL.
//
// The source is the profile owning the history service that changed, and
// the details is history::URLVisitedDetails.
NOTIFICATION_HISTORY_URL_VISITED,
// Sent when one or more URLs are deleted.
//
// The source is the profile owning the history service that changed, and
// the details is history::URLsDeletedDetails that lists the deleted URLs.
NOTIFICATION_HISTORY_URLS_DELETED,
// Sent when a keyword search term is updated. The source is the Profile and
// the details is history::KeywordSearchUpdatedDetails.
NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_UPDATED,
// Sent when a keyword search term is deleted. The source is the Profile and
// the details is history::KeywordSearchDeletedDetails.
NOTIFICATION_HISTORY_KEYWORD_SEARCH_TERM_DELETED,
// Sent by history when the favicon of a URL changes. The source is the
// profile, and the details is FaviconChangedDetails (see
// chrome/browser/favicon/favicon_changed_details.h).
NOTIFICATION_FAVICON_CHANGED,
// Sent by FaviconTabHelper when a tab's favicon has been successfully
// updated. The details are a bool indicating whether the
// NavigationEntry's favicon URL has changed since the previous
// NOTIFICATION_FAVICON_UPDATED notification. The details are true if
// there was no previous NOTIFICATION_FAVICON_UPDATED notification for the
// current NavigationEntry.
NOTIFICATION_FAVICON_UPDATED,
// Profiles -----------------------------------------------------------------
// Sent after a Profile has been created. This notification is sent both for
// normal and OTR profiles.
// The details are none and the source is the new profile.
NOTIFICATION_PROFILE_CREATED,
// Sent after a Profile has been added to ProfileManager.
// The details are none and the source is the new profile.
NOTIFICATION_PROFILE_ADDED,
// Sent before a Profile is destroyed. This notification is sent both for
// normal and OTR profiles.
// The details are none and the source is a Profile*.
NOTIFICATION_PROFILE_DESTROYED,
// Sent after the URLRequestContextGetter for a Profile has been initialized.
// The details are none and the source is a Profile*.
NOTIFICATION_PROFILE_URL_REQUEST_CONTEXT_GETTER_INITIALIZED,
// TopSites ----------------------------------------------------------------
// Sent by TopSites when it finishes loading. The source is the profile the
// details the TopSites.
NOTIFICATION_TOP_SITES_LOADED,
// Sent by TopSites when the either one of the most visited urls changed, or
// one of the images changes. The source is the TopSites, the details not
// used.
NOTIFICATION_TOP_SITES_CHANGED,
// Task Manager ------------------------------------------------------------
// Sent when a renderer process is notified of new v8 heap statistics. The
// source is the ID of the renderer process, and the details are a
// V8HeapStatsDetails object.
NOTIFICATION_RENDERER_V8_HEAP_STATS_COMPUTED,
// Non-history storage services --------------------------------------------
// Sent when a TemplateURL is removed from the model. The source is the
// Profile, and the details the id of the TemplateURL being removed.
NOTIFICATION_TEMPLATE_URL_REMOVED,
// Sent when the prefs relating to the default search engine have changed due
// to policy. Source and details are unused.
NOTIFICATION_DEFAULT_SEARCH_POLICY_CHANGED,
// The state of a web resource has been changed. A resource may have been
// added, removed, or altered. Source is WebResourceService, and the
// details are NoDetails.
NOTIFICATION_PROMO_RESOURCE_STATE_CHANGED,
// A safe browsing database update completed. Source is the
// SafeBrowsingService and the details are a bool indicating whether the
// update was successful.
NOTIFICATION_SAFE_BROWSING_UPDATE_COMPLETE,
// Autocomplete ------------------------------------------------------------
// Sent by the autocomplete controller when done. The source is the
// AutocompleteController, the details not used.
NOTIFICATION_AUTOCOMPLETE_CONTROLLER_RESULT_READY,
// This is sent when an item of the Omnibox popup is selected. The source
// is the profile.
NOTIFICATION_OMNIBOX_OPENED_URL,
// This is sent from Instant when the omnibox focus state changes.
NOTIFICATION_OMNIBOX_FOCUS_CHANGED,
// Sent when the Google URL for a profile has been updated. Some services
// cache this value and need to update themselves when it changes. See
// google_util::GetGoogleURLAndUpdateIfNecessary(). The source is the
// Profile, the details a GoogleURLTracker::UpdatedDetails containing the old
// and new URLs.
//
// Note that because incognito mode requests for the GoogleURLTracker are
// redirected to the non-incognito profile's copy, this notification will only
// ever fire on non-incognito profiles; thus listeners should use
// GetOriginalProfile() when constructing a Source to filter against.
NOTIFICATION_GOOGLE_URL_UPDATED,
// Printing ----------------------------------------------------------------
// Notification from PrintJob that an event occurred. It can be that a page
// finished printing or that the print job failed. Details is
// PrintJob::EventDetails. Source is a PrintJob.
NOTIFICATION_PRINT_JOB_EVENT,
// Sent when a PrintJob has been released.
// Source is the WebContents that holds the print job.
NOTIFICATION_PRINT_JOB_RELEASED,
// Shutdown ----------------------------------------------------------------
// Sent when WM_ENDSESSION has been received, after the browsers have been
// closed but before browser process has been shutdown. The source/details
// are all source and no details.
NOTIFICATION_SESSION_END,
// User Scripts ------------------------------------------------------------
// Sent when there are new user scripts available. The details are a
// pointer to SharedMemory containing the new scripts.
NOTIFICATION_USER_SCRIPTS_UPDATED,
// Extensions --------------------------------------------------------------
// Sent when a CrxInstaller finishes. Source is the CrxInstaller that
// finished. The details are the extension which was installed.
NOTIFICATION_CRX_INSTALLER_DONE,
// Sent when the known installed extensions have all been loaded. In
// testing scenarios this can happen multiple times if extensions are
// unloaded and reloaded. The source is a Profile.
NOTIFICATION_EXTENSIONS_READY,
// Sent when an extension icon being displayed in the location bar is updated.
// The source is the Profile and the details are the WebContents for
// the tab.
NOTIFICATION_EXTENSION_LOCATION_BAR_UPDATED,
// DEPRECATED: Use ExtensionRegistry::AddObserver instead.
//
// Sent when a new extension is loaded. The details are an Extension, and
// the source is a Profile.
NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
// An error occured while attempting to load an extension. The details are a
// string with details about why the load failed.
NOTIFICATION_EXTENSION_LOAD_ERROR,
// Sent when an extension is enabled. Under most circumstances, listeners
// will want to use NOTIFICATION_EXTENSION_LOADED_DEPRECATED. This
// notification is only
// fired when the "Enable" button is hit in the extensions tab. The details
// are an Extension, and the source is a Profile.
NOTIFICATION_EXTENSION_ENABLED,
// Sent when attempting to load a new extension, but they are disabled. The
// details are an Extension*, and the source is a Profile*.
NOTIFICATION_EXTENSION_UPDATE_DISABLED,
// Sent when an extension's permissions change. The details are an
// UpdatedExtensionPermissionsInfo, and the source is a Profile.
NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED,
// Sent when new extensions are installed, or existing extensions are updated.
// The details are an InstalledExtensionInfo, and the source is a Profile.
NOTIFICATION_EXTENSION_INSTALLED,
// An error occured during extension install. The details are a string with
// details about why the install failed.
NOTIFICATION_EXTENSION_INSTALL_ERROR,
// Sent when an extension has been uninstalled. The details are an Extension,
// and the source is a Profile.
NOTIFICATION_EXTENSION_UNINSTALLED,
// Sent when an extension uninstall is not allowed because the extension is
// not user manageable. The details are an Extension, and the source is a
// Profile.
NOTIFICATION_EXTENSION_UNINSTALL_NOT_ALLOWED,
// DEPRECATED: Use ExtensionRegistry::AddObserver instead.
//
// Sent when an extension is unloaded. This happens when an extension is
// uninstalled or disabled. The details are an UnloadedExtensionInfo, and
// the source is a Profile.
//
// Note that when this notification is sent, ExtensionService has already
// removed the extension from its internal state.
NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
// Sent when an Extension object is removed from ExtensionService. This
// can happen when an extension is uninstalled, upgraded, or blacklisted,
// including all cases when the Extension is deleted. The details are an
// Extension, and the source is a Profile.
NOTIFICATION_EXTENSION_REMOVED,
// Sent after a new ExtensionHost is created. The details are
// an ExtensionHost* and the source is a Profile*.
NOTIFICATION_EXTENSION_HOST_CREATED,
// Sent before an ExtensionHost is destroyed. The details are
// an ExtensionHost* and the source is a Profile*.
NOTIFICATION_EXTENSION_HOST_DESTROYED,
// Sent by an ExtensionHost when it has finished its initial page load,
// including any external resources.
// The details are an ExtensionHost* and the source is a Profile*.
NOTIFICATION_EXTENSION_HOST_DID_STOP_LOADING,
// Sent by an ExtensionHost when its render view requests closing through
// window.close(). The details are an ExtensionHost* and the source is a
// Profile*.
NOTIFICATION_EXTENSION_HOST_VIEW_SHOULD_CLOSE,
// Sent when extension render process ends (whether it crashes or closes).
// The details are an ExtensionHost* and the source is a Profile*. Not sent
// during browser shutdown.
NOTIFICATION_EXTENSION_PROCESS_TERMINATED,
// Sent when a background page is ready so other components can load.
NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
// Sent when a browser action's state has changed. The source is the
// ExtensionAction* that changed. The details are the Profile* that the
// browser action belongs to.
NOTIFICATION_EXTENSION_BROWSER_ACTION_UPDATED,
// Sent when the count of page actions has changed. Note that some of them
// may not apply to the current page. The source is a LocationBar*. There
// are no details.
NOTIFICATION_EXTENSION_PAGE_ACTION_COUNT_CHANGED,
// Sent when a browser action's visibility has changed. The source is the
// ExtensionPrefs* that changed, and the details are a std::string with the
// extension's ID.
NOTIFICATION_EXTENSION_BROWSER_ACTION_VISIBILITY_CHANGED,
// Sent when a page action's visibility has changed. The source is the
// ExtensionAction* that changed. The details are a WebContents*.
NOTIFICATION_EXTENSION_PAGE_ACTION_VISIBILITY_CHANGED,
// Sent when a system indicator action's state has changed. The source is the
// Profile* that the browser action belongs to. The details are the
// ExtensionAction* that changed.
NOTIFICATION_EXTENSION_SYSTEM_INDICATOR_UPDATED,
// Sent when an extension command has been removed. The source is the profile
// and the details is a std::pair of two std::string objects (an extension ID
// and the name of the command being removed).
NOTIFICATION_EXTENSION_COMMAND_REMOVED,
// Sent when an extension command has been added. The source is the profile
// and the details is a std::pair of two std::string objects (an extension ID
// and the name of the command being added).
NOTIFICATION_EXTENSION_COMMAND_ADDED,
// Sent when an extension command shortcut for a browser action is activated
// on Mac. The source is the profile and the details is a std::pair of a
// std::string containing an extension ID and a gfx::NativeWindow for the
// associated window.
NOTIFICATION_EXTENSION_COMMAND_BROWSER_ACTION_MAC,
// Sent when an extension command shortcut for a page action is activated
// on Mac. The source is the profile and the details is a std::pair of a
// std::string containing an extension ID and a gfx::NativeWindow for the
// associated window.
NOTIFICATION_EXTENSION_COMMAND_PAGE_ACTION_MAC,
// A new extension RenderViewHost has been registered. The details are
// the RenderViewHost*.
NOTIFICATION_EXTENSION_VIEW_REGISTERED,
// An extension RenderViewHost has been unregistered. The details are
// the RenderViewHost*.
NOTIFICATION_EXTENSION_VIEW_UNREGISTERED,
// Sent by an extension to notify the browser about the results of a unit
// test.
NOTIFICATION_EXTENSION_TEST_PASSED,
NOTIFICATION_EXTENSION_TEST_FAILED,
// Sent by extension test javascript code, typically in a browser test. The
// sender is a std::string representing the extension id, and the details
// are a std::string with some message. This is particularly useful when you
// want to have C++ code wait for javascript code to do something.
NOTIFICATION_EXTENSION_TEST_MESSAGE,
// Sent when an bookmarks extensions API function was successfully invoked.
// The source is the id of the extension that invoked the function, and the
// details are a pointer to the const BookmarksFunction in question.
NOTIFICATION_EXTENSION_BOOKMARKS_API_INVOKED,
// Sent when a downloads extensions API event is fired. The source is an
// ExtensionDownloadsEventRouter::NotificationSource, and the details is a
// std::string containing json. Used for testing.
NOTIFICATION_EXTENSION_DOWNLOADS_EVENT,
// Sent when an omnibox extension has sent back omnibox suggestions. The
// source is the profile, and the details are an
// extensions::api::omnibox::SendSuggestions::Params object.
NOTIFICATION_EXTENSION_OMNIBOX_SUGGESTIONS_READY,
// Sent when the user accepts the input in an extension omnibox keyword
// session. The source is the profile.
NOTIFICATION_EXTENSION_OMNIBOX_INPUT_ENTERED,
// Sent when an omnibox extension has updated the default suggestion. The
// source is the profile.
NOTIFICATION_EXTENSION_OMNIBOX_DEFAULT_SUGGESTION_CHANGED,
// Sent when the extension updater starts checking for updates to installed
// extensions. The source is a Profile, and there are no details.
NOTIFICATION_EXTENSION_UPDATING_STARTED,
// The extension updater found an update and will attempt to download and
// install it. The source is a Profile, and the details are an
// extensions::UpdateDetails object with the extension id and version of the
// found update.
NOTIFICATION_EXTENSION_UPDATE_FOUND,
// Upgrade notifications ---------------------------------------------------
// Sent when Chrome believes an update has been installed and available for
// long enough with the user shutting down to let it take effect. See
// upgrade_detector.cc for details on how long it waits. No details are
// expected.
NOTIFICATION_UPGRADE_RECOMMENDED,
// Sent when a critical update has been installed. No details are expected.
NOTIFICATION_CRITICAL_UPGRADE_INSTALLED,
// Sent when the current install is outdated. No details are expected.
NOTIFICATION_OUTDATED_INSTALL,
// Sent when the current install is outdated and auto-update (AU) is disabled.
// No details are expected.
NOTIFICATION_OUTDATED_INSTALL_NO_AU,
// Software incompatibility notifications ----------------------------------
// Sent when Chrome has finished compiling the list of loaded modules (and
// other modules of interest). No details are expected.
NOTIFICATION_MODULE_LIST_ENUMERATED,
// Sent when Chrome is done scanning the module list and when the user has
// acknowledged the module incompatibility. No details are expected.
NOTIFICATION_MODULE_INCOMPATIBILITY_BADGE_CHANGE,
// Content Settings --------------------------------------------------------
// Sent when content settings change. The source is a HostContentSettings
// object, the details are ContentSettingsNotificationsDetails.
NOTIFICATION_CONTENT_SETTINGS_CHANGED,
// Sent when the collect cookies dialog is shown. The source is a
// TabSpecificContentSettings object, there are no details.
NOTIFICATION_COLLECTED_COOKIES_SHOWN,
// Sent when a non-default setting in the the notification content settings
// map has changed. The source is the DesktopNotificationService, the
// details are None.
NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED,
// Sent when content settings change for a tab. The source is a
// content::WebContents object, the details are None.
NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
// Sync --------------------------------------------------------------------
// The sync service has finished the datatype configuration process. The
// source is the ProfileSyncService object of the Profile. There are no
// details.
NOTIFICATION_SYNC_CONFIGURE_DONE,
// A service is requesting a sync datatype refresh for the current profile.
// The details value is a const syncer::ModelTypeSet.
// If the payload map is empty, it should be treated as an invalidation for
// all enabled types. This is used by session sync.
NOTIFICATION_SYNC_REFRESH_LOCAL,
// External notification requesting a sync datatype refresh for the current
// profile. The details value is a const syncer::ObjectIdInvalidationMap.
// If the payload map is empty, it should be treated as an invalidation for
// all enabled types. This is used for notifications on Android.
NOTIFICATION_SYNC_REFRESH_REMOTE,
// The session service has been saved. This notification type is only sent
// if there were new SessionService commands to save, and not for no-op save
// operations.
NOTIFICATION_SESSION_SERVICE_SAVED,
// A foreign session has been updated. If a new tab page is open, the
// foreign session handler needs to update the new tab page's foreign
// session data.
NOTIFICATION_FOREIGN_SESSION_UPDATED,
// Foreign sessions has been disabled. New tabs should not display foreign
// session data.
NOTIFICATION_FOREIGN_SESSION_DISABLED,
// All tab metadata has been loaded from disk asynchronously.
// Sent on the UI thread.
// The source is the Profile. There are no details.
NOTIFICATION_SESSION_RESTORE_COMPLETE,
// Cookies -----------------------------------------------------------------
// Sent when a cookie changes. The source is a Profile object, the details
// are a ChromeCookieDetails object.
NOTIFICATION_COOKIE_CHANGED,
// Download Notifications --------------------------------------------------
// Sent when a download is initiated. It is possible that the download will
// not actually begin due to the DownloadRequestLimiter cancelling it
// prematurely.
// The source is the corresponding RenderViewHost. There are no details.
NOTIFICATION_DOWNLOAD_INITIATED,
// Misc --------------------------------------------------------------------
// Sent when PerformanceMonitor has finished all the initial steps of data
// collection and has begun passively observing. The source is the
// PerformanceMonitor*. No details are expected.
NOTIFICATION_PERFORMANCE_MONITOR_INITIALIZED,
#if defined(OS_CHROMEOS)
// Sent when a chromium os user logs in.
// The details are a chromeos::User object.
NOTIFICATION_LOGIN_USER_CHANGED,
// Sent immediately after the logged-in user's profile is ready.
// The details are a Profile object.
NOTIFICATION_LOGIN_USER_PROFILE_PREPARED,
// Sent when the chromium session of a particular user is started.
// If this is a new user on the machine this will not be sent until a profile
// picture has been selected, unlike NOTIFICATION_LOGIN_USER_CHANGED which is
// sent immediately after the user has logged in. This will be sent again if
// the browser crashes and restarts.
// The details are a chromeos::User object.
NOTIFICATION_SESSION_STARTED,
// Sent when user image is updated.
NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
// Sent by UserManager when a profile image download has been completed.
NOTIFICATION_PROFILE_IMAGE_UPDATED,
// Sent by UserManager when profile image download has failed or user has the
// default profile image or no profile image at all. No details are expected.
NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
// Sent when a chromium os user attempts to log in. The source is
// all and the details are AuthenticationNotificationDetails.
NOTIFICATION_LOGIN_AUTHENTICATION,
// Sent when a network error message is displayed on the WebUI login screen.
// First paint event of this fires NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE.
NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN,
// Sent when the specific part of login/lock WebUI is considered to be
// visible. That moment is tracked as the first paint event after one of the:
// NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN
//
// Possible series of notifications:
// 1. Boot into fresh OOBE
// NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE
// 2. Boot into user pods list (normal boot). Same for lock screen.
// NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE
// 3. Boot into GAIA sign in UI (user pods display disabled or no users):
// if no network is connected or flaky network
// (NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN +
// NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE)
// NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE
// 4. Boot into retail mode
// NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE
// 5. Boot into kiosk mode
// NOTIFICATION_KIOSK_APP_LAUNCHED
NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
// Sent when proxy dialog is closed.
NOTIFICATION_LOGIN_PROXY_CHANGED,
// Send when kiosk auto-launch warning screen is visible.
NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_VISIBLE,
// Send when kiosk auto-launch warning screen had completed.
NOTIFICATION_KIOSK_AUTOLAUNCH_WARNING_COMPLETED,
// Send when enable consumer kiosk warning screen is visible.
NOTIFICATION_KIOSK_ENABLE_WARNING_VISIBLE,
// Send when consumer kiosk has been enabled.
NOTIFICATION_KIOSK_ENABLED,
// Send when enable consumer kiosk warning screen had completed.
NOTIFICATION_KIOSK_ENABLE_WARNING_COMPLETED,
// Sent when kiosk app list is loaded in UI.
NOTIFICATION_KIOSK_APPS_LOADED,
// Sent when a kiosk app is launched.
NOTIFICATION_KIOSK_APP_LAUNCHED,
// Sent when the user list has changed.
NOTIFICATION_USER_LIST_CHANGED,
// Sent when the screen lock state has changed. The source is
// ScreenLocker and the details is a bool specifing that the
// screen is locked. When details is a false, the source object
// is being deleted, so the receiver shouldn't use the screen locker
// object.
NOTIFICATION_SCREEN_LOCK_STATE_CHANGED,
// Sent by DeviceSettingsService to indicate that the ownership status
// changed. If you can, please use DeviceSettingsService::Observer instead.
// Other singleton-based services can't use that because Observer
// unregistration is impossible due to unpredictable deletion order.
NOTIFICATION_OWNERSHIP_STATUS_CHANGED,
// Sent by SIM unlock dialog when it has finished with the process of
// updating RequirePin setting. RequirePin setting might have been changed
// to a new value or update might have been canceled.
// In either case notification is sent and details contain a bool
// that represents current value.
NOTIFICATION_REQUIRE_PIN_SETTING_CHANGE_ENDED,
// Sent by SIM unlock dialog when it has finished the EnterPin or
// EnterPuk dialog, either because the user cancelled, or entered a
// PIN or PUK.
NOTIFICATION_ENTER_PIN_ENDED,
#endif
#if defined(TOOLKIT_VIEWS)
// Sent when a bookmark's context menu is shown. Used to notify
// tests that the context menu has been created and shown.
NOTIFICATION_BOOKMARK_CONTEXT_MENU_SHOWN,
// Notification that the nested loop using during tab dragging has returned.
// Used for testing.
NOTIFICATION_TAB_DRAG_LOOP_DONE,
#endif
// Send when a context menu is shown. Used to notify tests that the context
// menu has been created and shown.
NOTIFICATION_RENDER_VIEW_CONTEXT_MENU_SHOWN,
// Sent when the Instant Controller determines whether an Instant tab supports
// the Instant API or not.
NOTIFICATION_INSTANT_TAB_SUPPORT_DETERMINED,
// Sent when the Instant Controller determines whether the NTP supports the
// Instant API or not.
NOTIFICATION_INSTANT_NTP_SUPPORT_DETERMINED,
// Sent when the CaptivePortalService checks if we're behind a captive portal.
// The Source is the Profile the CaptivePortalService belongs to, and the
// Details are a Details<CaptivePortalService::CheckResults>.
NOTIFICATION_CAPTIVE_PORTAL_CHECK_RESULT,
// Sent when the applications in the NTP app launcher have been reordered.
// The details, if not NoDetails, is the std::string ID of the extension that
// was moved.
NOTIFICATION_EXTENSION_LAUNCHER_REORDERED,
// Sent when an app is installed and an NTP has been shown. Source is the
// WebContents that was shown, and Details is the string ID of the extension
// which was installed.
NOTIFICATION_APP_INSTALLED_TO_NTP,
// Similar to NOTIFICATION_APP_INSTALLED_TO_NTP but used to nofity ash AppList
// about installed app. Source is the profile in which the app is installed
// and Details is the string ID of the extension.
NOTIFICATION_APP_INSTALLED_TO_APPLIST,
#if defined(USE_ASH)
// Sent when wallpaper show animation has finished.
NOTIFICATION_WALLPAPER_ANIMATION_FINISHED,
// Sent when the Ash session has started. In its current incantation this is
// generated when the metro app has connected to the browser IPC channel.
// Used only on Windows.
NOTIFICATION_ASH_SESSION_STARTED,
// Sent when the Ash session ended. Currently this means the metro app exited.
// Used only on Windows.
NOTIFICATION_ASH_SESSION_ENDED,
#endif
// Protocol Handler Registry -----------------------------------------------
// Sent when a ProtocolHandlerRegistry is changed. The source is the profile.
NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED,
// Sent when the cached profile info has changed.
NOTIFICATION_PROFILE_CACHED_INFO_CHANGED,
// Sent when the cached profile has finished writing a profile picture to
// disk.
NOTIFICATION_PROFILE_CACHE_PICTURE_SAVED,
// Sent when the browser enters or exits fullscreen mode.
NOTIFICATION_FULLSCREEN_CHANGED,
// Sent when the FullscreenController changes, confirms, or denies mouse lock.
// The source is the browser's FullscreenController, no details.
NOTIFICATION_MOUSE_LOCK_CHANGED,
// Sent by the PluginPrefs when there is a change of plugin enable/disable
// status. The source is the profile.
NOTIFICATION_PLUGIN_ENABLE_STATUS_CHANGED,
// Panels Notifications. The Panels are small browser windows near the bottom
// of the screen.
// Sent when all nonblocking bounds animations are finished across panels.
// Used only in unit testing.
NOTIFICATION_PANEL_BOUNDS_ANIMATIONS_FINISHED,
// Sent when panel gains/loses focus.
// The source is the Panel, no details.
// Used only in unit testing.
NOTIFICATION_PANEL_CHANGED_ACTIVE_STATUS,
// Sent when panel is minimized/restored/shows title only etc.
// The source is the Panel, no details.
NOTIFICATION_PANEL_CHANGED_EXPANSION_STATE,
// Sent when panel window size is known. This is for platforms where the
// window creation is async and size of the window only becomes known later.
// Used only in unit testing.
NOTIFICATION_PANEL_WINDOW_SIZE_KNOWN,
// Sent when panel app icon is loaded.
// Used only in unit testing.
NOTIFICATION_PANEL_APP_ICON_LOADED,
// Sent when panel collection get updated.
// The source is the PanelCollection, no details.
// Used only in coordination with notification balloons.
NOTIFICATION_PANEL_COLLECTION_UPDATED,
// Sent when panel is closed.
// The source is the Panel, no details.
NOTIFICATION_PANEL_CLOSED,
// Sent when a global error has changed and the error UI should update it
// self. The source is a Source<Profile> containing the profile for the
// error. The detail is a GlobalError object that has changed or NULL if
// all error UIs should update.
NOTIFICATION_GLOBAL_ERRORS_CHANGED,
// BrowsingDataRemover ----------------------------------------------------
// Sent on the UI thread after BrowsingDataRemover has removed browsing data
// but before it has notified its explicit observers. The source is a
// Source<Profile> containing the profile in which browsing data was removed,
// and the detail is a BrowsingDataRemover::NotificationDetail containing the
// removal mask and the start of the removal timeframe with which
// BrowsingDataRemove::Remove was called.
NOTIFICATION_BROWSING_DATA_REMOVED,
// The user accepted or dismissed a SSL client authentication request.
// The source is a Source<net::HttpNetworkSession>. Details is a
// (std::pair<net::SSLCertRequestInfo*, net::X509Certificate*>).
NOTIFICATION_SSL_CLIENT_AUTH_CERT_SELECTED,
// Session Restore --------------------------------------------------------
// Sent when synchronous (startup) session restore completes. No details or
// source.
NOTIFICATION_SESSION_RESTORE_DONE,
// Note:-
// Currently only Content and Chrome define and use notifications.
// Custom notifications not belonging to Content and Chrome should start
// from here.
NOTIFICATION_CHROME_END,
};
} // namespace chrome
#endif // CHROME_BROWSER_CHROME_NOTIFICATION_TYPES_H_

View file

@ -0,0 +1,363 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/printing/print_job.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/message_loop/message_loop.h"
#include "base/threading/thread_restrictions.h"
#include "base/threading/worker_pool.h"
#include "base/timer/timer.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/printing/print_job_worker.h"
#include "content/public/browser/notification_service.h"
#include "printing/printed_document.h"
#include "printing/printed_page.h"
using base::TimeDelta;
namespace {
// Helper function to ensure |owner| is valid until at least |callback| returns.
void HoldRefCallback(const scoped_refptr<printing::PrintJobWorkerOwner>& owner,
const base::Closure& callback) {
callback.Run();
}
} // namespace
namespace printing {
PrintJob::PrintJob()
: ui_message_loop_(base::MessageLoop::current()),
source_(NULL),
worker_(),
settings_(),
is_job_pending_(false),
is_canceling_(false),
quit_factory_(this) {
DCHECK(ui_message_loop_);
// This is normally a UI message loop, but in unit tests, the message loop is
// of the 'default' type.
DCHECK(base::MessageLoopForUI::IsCurrent() ||
ui_message_loop_->type() == base::MessageLoop::TYPE_DEFAULT);
ui_message_loop_->AddDestructionObserver(this);
}
PrintJob::~PrintJob() {
ui_message_loop_->RemoveDestructionObserver(this);
// The job should be finished (or at least canceled) when it is destroyed.
DCHECK(!is_job_pending_);
DCHECK(!is_canceling_);
if (worker_.get())
DCHECK(worker_->message_loop() == NULL);
DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
}
void PrintJob::Initialize(PrintJobWorkerOwner* job,
PrintedPagesSource* source,
int page_count) {
DCHECK(!source_);
DCHECK(!worker_.get());
DCHECK(!is_job_pending_);
DCHECK(!is_canceling_);
DCHECK(!document_.get());
source_ = source;
worker_.reset(job->DetachWorker(this));
settings_ = job->settings();
PrintedDocument* new_doc =
new PrintedDocument(settings_, source_, job->cookie());
new_doc->set_page_count(page_count);
UpdatePrintedDocument(new_doc);
// Don't forget to register to our own messages.
registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT,
content::Source<PrintJob>(this));
}
void PrintJob::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
switch (type) {
case chrome::NOTIFICATION_PRINT_JOB_EVENT: {
OnNotifyPrintJobEvent(*content::Details<JobEventDetails>(details).ptr());
break;
}
default: {
break;
}
}
}
void PrintJob::GetSettingsDone(const PrintSettings& new_settings,
PrintingContext::Result result) {
NOTREACHED();
}
PrintJobWorker* PrintJob::DetachWorker(PrintJobWorkerOwner* new_owner) {
NOTREACHED();
return NULL;
}
base::MessageLoop* PrintJob::message_loop() {
return ui_message_loop_;
}
const PrintSettings& PrintJob::settings() const {
return settings_;
}
int PrintJob::cookie() const {
if (!document_.get())
// Always use an invalid cookie in this case.
return 0;
return document_->cookie();
}
void PrintJob::WillDestroyCurrentMessageLoop() {
NOTREACHED();
}
void PrintJob::StartPrinting() {
DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
DCHECK(worker_->message_loop());
DCHECK(!is_job_pending_);
if (!worker_->message_loop() || is_job_pending_)
return;
// Real work is done in PrintJobWorker::StartPrinting().
worker_->message_loop()->PostTask(
FROM_HERE,
base::Bind(&HoldRefCallback, make_scoped_refptr(this),
base::Bind(&PrintJobWorker::StartPrinting,
base::Unretained(worker_.get()), document_)));
// Set the flag right now.
is_job_pending_ = true;
// Tell everyone!
scoped_refptr<JobEventDetails> details(
new JobEventDetails(JobEventDetails::NEW_DOC, document_.get(), NULL));
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_PRINT_JOB_EVENT,
content::Source<PrintJob>(this),
content::Details<JobEventDetails>(details.get()));
}
void PrintJob::Stop() {
DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
if (quit_factory_.HasWeakPtrs()) {
// In case we're running a nested message loop to wait for a job to finish,
// and we finished before the timeout, quit the nested loop right away.
Quit();
quit_factory_.InvalidateWeakPtrs();
}
// Be sure to live long enough.
scoped_refptr<PrintJob> handle(this);
if (worker_->message_loop()) {
ControlledWorkerShutdown();
} else {
// Flush the cached document.
UpdatePrintedDocument(NULL);
}
}
void PrintJob::Cancel() {
if (is_canceling_)
return;
is_canceling_ = true;
// Be sure to live long enough.
scoped_refptr<PrintJob> handle(this);
DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
base::MessageLoop* worker_loop =
worker_.get() ? worker_->message_loop() : NULL;
if (worker_loop) {
// Call this right now so it renders the context invalid. Do not use
// InvokeLater since it would take too much time.
worker_->Cancel();
}
// Make sure a Cancel() is broadcast.
scoped_refptr<JobEventDetails> details(
new JobEventDetails(JobEventDetails::FAILED, NULL, NULL));
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_PRINT_JOB_EVENT,
content::Source<PrintJob>(this),
content::Details<JobEventDetails>(details.get()));
Stop();
is_canceling_ = false;
}
bool PrintJob::FlushJob(base::TimeDelta timeout) {
// Make sure the object outlive this message loop.
scoped_refptr<PrintJob> handle(this);
base::MessageLoop::current()->PostDelayedTask(FROM_HERE,
base::Bind(&PrintJob::Quit, quit_factory_.GetWeakPtr()), timeout);
base::MessageLoop::ScopedNestableTaskAllower allow(
base::MessageLoop::current());
base::MessageLoop::current()->Run();
return true;
}
void PrintJob::DisconnectSource() {
source_ = NULL;
if (document_.get())
document_->DisconnectSource();
}
bool PrintJob::is_job_pending() const {
return is_job_pending_;
}
PrintedDocument* PrintJob::document() const {
return document_.get();
}
void PrintJob::UpdatePrintedDocument(PrintedDocument* new_document) {
if (document_.get() == new_document)
return;
document_ = new_document;
if (document_.get()) {
settings_ = document_->settings();
}
if (worker_.get() && worker_->message_loop()) {
DCHECK(!is_job_pending_);
// Sync the document with the worker.
worker_->message_loop()->PostTask(
FROM_HERE,
base::Bind(&HoldRefCallback, make_scoped_refptr(this),
base::Bind(&PrintJobWorker::OnDocumentChanged,
base::Unretained(worker_.get()), document_)));
}
}
void PrintJob::OnNotifyPrintJobEvent(const JobEventDetails& event_details) {
switch (event_details.type()) {
case JobEventDetails::FAILED: {
settings_.Clear();
// No need to cancel since the worker already canceled itself.
Stop();
break;
}
case JobEventDetails::USER_INIT_DONE:
case JobEventDetails::DEFAULT_INIT_DONE:
case JobEventDetails::USER_INIT_CANCELED: {
DCHECK_EQ(event_details.document(), document_.get());
break;
}
case JobEventDetails::NEW_DOC:
case JobEventDetails::NEW_PAGE:
case JobEventDetails::PAGE_DONE:
case JobEventDetails::JOB_DONE:
case JobEventDetails::ALL_PAGES_REQUESTED: {
// Don't care.
break;
}
case JobEventDetails::DOC_DONE: {
// This will call Stop() and broadcast a JOB_DONE message.
base::MessageLoop::current()->PostTask(
FROM_HERE, base::Bind(&PrintJob::OnDocumentDone, this));
break;
}
default: {
NOTREACHED();
break;
}
}
}
void PrintJob::OnDocumentDone() {
// Be sure to live long enough. The instance could be destroyed by the
// JOB_DONE broadcast.
scoped_refptr<PrintJob> handle(this);
// Stop the worker thread.
Stop();
scoped_refptr<JobEventDetails> details(
new JobEventDetails(JobEventDetails::JOB_DONE, document_.get(), NULL));
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_PRINT_JOB_EVENT,
content::Source<PrintJob>(this),
content::Details<JobEventDetails>(details.get()));
}
void PrintJob::ControlledWorkerShutdown() {
DCHECK_EQ(ui_message_loop_, base::MessageLoop::current());
// The deadlock this code works around is specific to window messaging on
// Windows, so we aren't likely to need it on any other platforms.
#if defined(OS_WIN)
// We could easily get into a deadlock case if worker_->Stop() is used; the
// printer driver created a window as a child of the browser window. By
// canceling the job, the printer driver initiated dialog box is destroyed,
// which sends a blocking message to its parent window. If the browser window
// thread is not processing messages, a deadlock occurs.
//
// This function ensures that the dialog box will be destroyed in a timely
// manner by the mere fact that the thread will terminate. So the potential
// deadlock is eliminated.
worker_->StopSoon();
// Delay shutdown until the worker terminates. We want this code path
// to wait on the thread to quit before continuing.
if (worker_->IsRunning()) {
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&PrintJob::ControlledWorkerShutdown, this),
base::TimeDelta::FromMilliseconds(100));
return;
}
#endif
// Now make sure the thread object is cleaned up. Do this on a worker
// thread because it may block.
base::WorkerPool::PostTaskAndReply(
FROM_HERE,
base::Bind(&PrintJobWorker::Stop, base::Unretained(worker_.get())),
base::Bind(&PrintJob::HoldUntilStopIsCalled, this),
false);
is_job_pending_ = false;
registrar_.RemoveAll();
UpdatePrintedDocument(NULL);
}
void PrintJob::HoldUntilStopIsCalled() {
}
void PrintJob::Quit() {
base::MessageLoop::current()->Quit();
}
// Takes settings_ ownership and will be deleted in the receiving thread.
JobEventDetails::JobEventDetails(Type type,
PrintedDocument* document,
PrintedPage* page)
: document_(document),
page_(page),
type_(type) {
}
JobEventDetails::~JobEventDetails() {
}
PrintedDocument* JobEventDetails::document() const { return document_.get(); }
PrintedPage* JobEventDetails::page() const { return page_.get(); }
} // namespace printing

View file

@ -0,0 +1,212 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PRINTING_PRINT_JOB_H_
#define CHROME_BROWSER_PRINTING_PRINT_JOB_H_
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "chrome/browser/printing/print_job_worker_owner.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
class Thread;
namespace printing {
// See definition below.
class JobEventDetails;
class PrintedDocument;
class PrintedPage;
class PrintedPagesSource;
class PrintJobWorker;
class PrinterQuery;
// Manages the print work for a specific document. Talks to the printer through
// PrintingContext through PrintJobWorker. Hides access to PrintingContext in a
// worker thread so the caller never blocks. PrintJob will send notifications on
// any state change. While printing, the PrintJobManager instance keeps a
// reference to the job to be sure it is kept alive. All the code in this class
// runs in the UI thread.
class PrintJob : public PrintJobWorkerOwner,
public content::NotificationObserver,
public base::MessageLoop::DestructionObserver {
public:
// Create a empty PrintJob. When initializing with this constructor,
// post-constructor initialization must be done with Initialize().
PrintJob();
// Grabs the ownership of the PrintJobWorker from another job, which is
// usually a PrinterQuery. Set the expected page count of the print job.
void Initialize(PrintJobWorkerOwner* job, PrintedPagesSource* source,
int page_count);
// content::NotificationObserver implementation.
virtual void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE;
// PrintJobWorkerOwner implementation.
virtual void GetSettingsDone(const PrintSettings& new_settings,
PrintingContext::Result result) OVERRIDE;
virtual PrintJobWorker* DetachWorker(PrintJobWorkerOwner* new_owner) OVERRIDE;
virtual base::MessageLoop* message_loop() OVERRIDE;
virtual const PrintSettings& settings() const OVERRIDE;
virtual int cookie() const OVERRIDE;
// DestructionObserver implementation.
virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
// Starts the actual printing. Signals the worker that it should begin to
// spool as soon as data is available.
void StartPrinting();
// Asks for the worker thread to finish its queued tasks and disconnects the
// delegate object. The PrintJobManager will remove its reference. This may
// have the side-effect of destroying the object if the caller doesn't have a
// handle to the object. Use PrintJob::is_stopped() to check whether the
// worker thread has actually stopped.
void Stop();
// Cancels printing job and stops the worker thread. Takes effect immediately.
void Cancel();
// Synchronously wait for the job to finish. It is mainly useful when the
// process is about to be shut down and we're waiting for the spooler to eat
// our data.
bool FlushJob(base::TimeDelta timeout);
// Disconnects the PrintedPage source (PrintedPagesSource). It is done when
// the source is being destroyed.
void DisconnectSource();
// Returns true if the print job is pending, i.e. between a StartPrinting()
// and the end of the spooling.
bool is_job_pending() const;
// Access the current printed document. Warning: may be NULL.
PrintedDocument* document() const;
protected:
virtual ~PrintJob();
private:
// Updates document_ to a new instance.
void UpdatePrintedDocument(PrintedDocument* new_document);
// Processes a NOTIFY_PRINT_JOB_EVENT notification.
void OnNotifyPrintJobEvent(const JobEventDetails& event_details);
// Releases the worker thread by calling Stop(), then broadcasts a JOB_DONE
// notification.
void OnDocumentDone();
// Terminates the worker thread in a very controlled way, to work around any
// eventual deadlock.
void ControlledWorkerShutdown();
// Called at shutdown when running a nested message loop.
void Quit();
void HoldUntilStopIsCalled();
content::NotificationRegistrar registrar_;
// Main message loop reference. Used to send notifications in the right
// thread.
base::MessageLoop* const ui_message_loop_;
// Source that generates the PrintedPage's (i.e. a WebContents). It will be
// set back to NULL if the source is deleted before this object.
PrintedPagesSource* source_;
// All the UI is done in a worker thread because many Win32 print functions
// are blocking and enters a message loop without your consent. There is one
// worker thread per print job.
scoped_ptr<PrintJobWorker> worker_;
// Cache of the print context settings for access in the UI thread.
PrintSettings settings_;
// The printed document.
scoped_refptr<PrintedDocument> document_;
// Is the worker thread printing.
bool is_job_pending_;
// Is Canceling? If so, try to not cause recursion if on FAILED notification,
// the notified calls Cancel() again.
bool is_canceling_;
// Used at shutdown so that we can quit a nested message loop.
base::WeakPtrFactory<PrintJob> quit_factory_;
DISALLOW_COPY_AND_ASSIGN(PrintJob);
};
// Details for a NOTIFY_PRINT_JOB_EVENT notification. The members may be NULL.
class JobEventDetails : public base::RefCountedThreadSafe<JobEventDetails> {
public:
// Event type.
enum Type {
// Print... dialog box has been closed with OK button.
USER_INIT_DONE,
// Print... dialog box has been closed with CANCEL button.
USER_INIT_CANCELED,
// An automated initialization has been done, e.g. Init(false, NULL).
DEFAULT_INIT_DONE,
// A new document started printing.
NEW_DOC,
// A new page started printing.
NEW_PAGE,
// A page is done printing.
PAGE_DONE,
// A document is done printing. The worker thread is still alive. Warning:
// not a good moment to release the handle to PrintJob.
DOC_DONE,
// The worker thread is finished. A good moment to release the handle to
// PrintJob.
JOB_DONE,
// All missing pages have been requested.
ALL_PAGES_REQUESTED,
// An error occured. Printing is canceled.
FAILED,
};
JobEventDetails(Type type, PrintedDocument* document, PrintedPage* page);
// Getters.
PrintedDocument* document() const;
PrintedPage* page() const;
Type type() const {
return type_;
}
private:
friend class base::RefCountedThreadSafe<JobEventDetails>;
~JobEventDetails();
scoped_refptr<PrintedDocument> document_;
scoped_refptr<PrintedPage> page_;
const Type type_;
DISALLOW_COPY_AND_ASSIGN(JobEventDetails);
};
} // namespace printing
#endif // CHROME_BROWSER_PRINTING_PRINT_JOB_H_

View file

@ -0,0 +1,159 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/printing/print_job_manager.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/printing/print_job.h"
#include "chrome/browser/printing/printer_query.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
#include "printing/printed_document.h"
#include "printing/printed_page.h"
namespace printing {
PrintQueriesQueue::PrintQueriesQueue() {
}
PrintQueriesQueue::~PrintQueriesQueue() {
base::AutoLock lock(lock_);
queued_queries_.clear();
}
void PrintQueriesQueue::SetDestination(PrintDestinationInterface* destination) {
base::AutoLock lock(lock_);
destination_ = destination;
}
void PrintQueriesQueue::QueuePrinterQuery(PrinterQuery* job) {
base::AutoLock lock(lock_);
DCHECK(job);
queued_queries_.push_back(make_scoped_refptr(job));
DCHECK(job->is_valid());
}
scoped_refptr<PrinterQuery> PrintQueriesQueue::PopPrinterQuery(
int document_cookie) {
base::AutoLock lock(lock_);
for (PrinterQueries::iterator itr = queued_queries_.begin();
itr != queued_queries_.end(); ++itr) {
if ((*itr)->cookie() == document_cookie && !(*itr)->is_callback_pending()) {
scoped_refptr<printing::PrinterQuery> current_query(*itr);
queued_queries_.erase(itr);
DCHECK(current_query->is_valid());
return current_query;
}
}
return NULL;
}
scoped_refptr<PrinterQuery> PrintQueriesQueue::CreatePrinterQuery() {
scoped_refptr<PrinterQuery> job = new printing::PrinterQuery;
base::AutoLock lock(lock_);
job->SetWorkerDestination(destination_);
return job;
}
void PrintQueriesQueue::Shutdown() {
base::AutoLock lock(lock_);
queued_queries_.clear();
destination_ = NULL;
}
PrintJobManager::PrintJobManager() : is_shutdown_(false) {
registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_EVENT,
content::NotificationService::AllSources());
}
PrintJobManager::~PrintJobManager() {
}
scoped_refptr<PrintQueriesQueue> PrintJobManager::queue() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if (!queue_)
queue_ = new PrintQueriesQueue();
return queue_;
}
void PrintJobManager::Shutdown() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
DCHECK(!is_shutdown_);
is_shutdown_ = true;
registrar_.RemoveAll();
StopJobs(true);
if (queue_)
queue_->Shutdown();
queue_ = NULL;
}
void PrintJobManager::StopJobs(bool wait_for_finish) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
// Copy the array since it can be modified in transit.
PrintJobs to_stop;
to_stop.swap(current_jobs_);
for (PrintJobs::const_iterator job = to_stop.begin(); job != to_stop.end();
++job) {
// Wait for two minutes for the print job to be spooled.
if (wait_for_finish)
(*job)->FlushJob(base::TimeDelta::FromMinutes(2));
(*job)->Stop();
}
}
void PrintJobManager::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
switch (type) {
case chrome::NOTIFICATION_PRINT_JOB_EVENT: {
OnPrintJobEvent(content::Source<PrintJob>(source).ptr(),
*content::Details<JobEventDetails>(details).ptr());
break;
}
default: {
NOTREACHED();
break;
}
}
}
void PrintJobManager::OnPrintJobEvent(
PrintJob* print_job,
const JobEventDetails& event_details) {
switch (event_details.type()) {
case JobEventDetails::NEW_DOC: {
DCHECK(current_jobs_.end() == current_jobs_.find(print_job));
// Causes a AddRef().
current_jobs_.insert(print_job);
break;
}
case JobEventDetails::JOB_DONE: {
DCHECK(current_jobs_.end() != current_jobs_.find(print_job));
current_jobs_.erase(print_job);
break;
}
case JobEventDetails::FAILED: {
current_jobs_.erase(print_job);
break;
}
case JobEventDetails::USER_INIT_DONE:
case JobEventDetails::USER_INIT_CANCELED:
case JobEventDetails::DEFAULT_INIT_DONE:
case JobEventDetails::NEW_PAGE:
case JobEventDetails::PAGE_DONE:
case JobEventDetails::DOC_DONE:
case JobEventDetails::ALL_PAGES_REQUESTED: {
// Don't care.
break;
}
default: {
NOTREACHED();
break;
}
}
}
} // namespace printing

View file

@ -0,0 +1,104 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PRINTING_PRINT_JOB_MANAGER_H_
#define CHROME_BROWSER_PRINTING_PRINT_JOB_MANAGER_H_
#include <set>
#include <vector>
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/synchronization/lock.h"
#include "base/threading/non_thread_safe.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "printing/print_destination_interface.h"
namespace printing {
class JobEventDetails;
class PrintJob;
class PrinterQuery;
class PrintQueriesQueue : public base::RefCountedThreadSafe<PrintQueriesQueue> {
public:
PrintQueriesQueue();
// Sets the print destination to be set on the next print job.
void SetDestination(PrintDestinationInterface* destination);
// Queues a semi-initialized worker thread. Can be called from any thread.
// Current use case is queuing from the I/O thread.
// TODO(maruel): Have them vanish after a timeout (~5 minutes?)
void QueuePrinterQuery(PrinterQuery* job);
// Pops a queued PrintJobWorkerOwner object that was previously queued or
// create new one. Can be called from any thread.
scoped_refptr<PrinterQuery> PopPrinterQuery(int document_cookie);
// Creates new query.
scoped_refptr<PrinterQuery> CreatePrinterQuery();
void Shutdown();
private:
friend class base::RefCountedThreadSafe<PrintQueriesQueue>;
typedef std::vector<scoped_refptr<PrinterQuery> > PrinterQueries;
virtual ~PrintQueriesQueue();
// Used to serialize access to queued_workers_.
base::Lock lock_;
PrinterQueries queued_queries_;
scoped_refptr<PrintDestinationInterface> destination_;
DISALLOW_COPY_AND_ASSIGN(PrintQueriesQueue);
};
class PrintJobManager : public content::NotificationObserver {
public:
PrintJobManager();
virtual ~PrintJobManager();
// On browser quit, we should wait to have the print job finished.
void Shutdown();
// content::NotificationObserver
virtual void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE;
// Returns queries queue. Never returns NULL. Must be called on Browser UI
// Thread. Reference could be stored and used from any thread.
scoped_refptr<PrintQueriesQueue> queue();
private:
typedef std::set<scoped_refptr<PrintJob> > PrintJobs;
// Processes a NOTIFY_PRINT_JOB_EVENT notification.
void OnPrintJobEvent(PrintJob* print_job,
const JobEventDetails& event_details);
// Stops all printing jobs. If wait_for_finish is true, tries to give jobs
// a chance to complete before stopping them.
void StopJobs(bool wait_for_finish);
content::NotificationRegistrar registrar_;
// Current print jobs that are active.
PrintJobs current_jobs_;
scoped_refptr<PrintQueriesQueue> queue_;
bool is_shutdown_;
DISALLOW_COPY_AND_ASSIGN(PrintJobManager);
};
} // namespace printing
#endif // CHROME_BROWSER_PRINTING_PRINT_JOB_MANAGER_H_

View file

@ -0,0 +1,387 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/printing/print_job_worker.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/message_loop/message_loop.h"
#include "base/values.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/printing_ui_web_contents_observer.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
#include "grit/generated_resources.h"
#include "printing/print_job_constants.h"
#include "printing/printed_document.h"
#include "printing/printed_page.h"
#include "printing/printing_utils.h"
#include "ui/base/l10n/l10n_util.h"
using content::BrowserThread;
namespace {
// Helper function to ensure |owner| is valid until at least |callback| returns.
void HoldRefCallback(const scoped_refptr<printing::PrintJobWorkerOwner>& owner,
const base::Closure& callback) {
callback.Run();
}
} // namespace
namespace printing {
void NotificationCallback(PrintJobWorkerOwner* print_job,
JobEventDetails::Type detail_type,
PrintedDocument* document,
PrintedPage* page) {
JobEventDetails* details = new JobEventDetails(detail_type, document, page);
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_PRINT_JOB_EVENT,
// We know that is is a PrintJob object in this circumstance.
content::Source<PrintJob>(static_cast<PrintJob*>(print_job)),
content::Details<JobEventDetails>(details));
}
PrintJobWorker::PrintJobWorker(PrintJobWorkerOwner* owner)
: Thread("Printing_Worker"),
owner_(owner),
weak_factory_(this) {
// The object is created in the IO thread.
DCHECK_EQ(owner_->message_loop(), base::MessageLoop::current());
printing_context_.reset(PrintingContext::Create(
g_browser_process->GetApplicationLocale()));
}
PrintJobWorker::~PrintJobWorker() {
// The object is normally deleted in the UI thread, but when the user
// cancels printing or in the case of print preview, the worker is destroyed
// on the I/O thread.
DCHECK_EQ(owner_->message_loop(), base::MessageLoop::current());
Stop();
}
void PrintJobWorker::SetNewOwner(PrintJobWorkerOwner* new_owner) {
DCHECK(page_number_ == PageNumber::npos());
owner_ = new_owner;
}
void PrintJobWorker::SetPrintDestination(
PrintDestinationInterface* destination) {
destination_ = destination;
}
void PrintJobWorker::GetSettings(
bool ask_user_for_settings,
scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
int document_page_count,
bool has_selection,
MarginType margin_type) {
DCHECK_EQ(message_loop(), base::MessageLoop::current());
DCHECK_EQ(page_number_, PageNumber::npos());
// Recursive task processing is needed for the dialog in case it needs to be
// destroyed by a task.
// TODO(thestig): This code is wrong. SetNestableTasksAllowed(true) is needed
// on the thread where the PrintDlgEx is called, and definitely both calls
// should happen on the same thread. See http://crbug.com/73466
// MessageLoop::current()->SetNestableTasksAllowed(true);
printing_context_->set_margin_type(margin_type);
// When we delegate to a destination, we don't ask the user for settings.
// TODO(mad): Ask the destination for settings.
if (ask_user_for_settings && destination_.get() == NULL) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&HoldRefCallback, make_scoped_refptr(owner_),
base::Bind(&PrintJobWorker::GetSettingsWithUI,
base::Unretained(this),
base::Passed(&web_contents_observer),
document_page_count,
has_selection)));
} else {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&HoldRefCallback, make_scoped_refptr(owner_),
base::Bind(&PrintJobWorker::UseDefaultSettings,
base::Unretained(this))));
}
}
void PrintJobWorker::SetSettings(
const base::DictionaryValue* const new_settings) {
DCHECK_EQ(message_loop(), base::MessageLoop::current());
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&HoldRefCallback, make_scoped_refptr(owner_),
base::Bind(&PrintJobWorker::UpdatePrintSettings,
base::Unretained(this), new_settings)));
}
void PrintJobWorker::UpdatePrintSettings(
const base::DictionaryValue* const new_settings) {
// Create new PageRanges based on |new_settings|.
PageRanges new_ranges;
const base::ListValue* page_range_array;
if (new_settings->GetList(kSettingPageRange, &page_range_array)) {
for (size_t index = 0; index < page_range_array->GetSize(); ++index) {
const base::DictionaryValue* dict;
if (!page_range_array->GetDictionary(index, &dict))
continue;
PageRange range;
if (!dict->GetInteger(kSettingPageRangeFrom, &range.from) ||
!dict->GetInteger(kSettingPageRangeTo, &range.to)) {
continue;
}
// Page numbers are 1-based in the dictionary.
// Page numbers are 0-based for the printing context.
range.from--;
range.to--;
new_ranges.push_back(range);
}
}
PrintingContext::Result result =
printing_context_->UpdatePrintSettings(*new_settings, new_ranges);
delete new_settings;
GetSettingsDone(result);
}
void PrintJobWorker::GetSettingsDone(PrintingContext::Result result) {
// Most PrintingContext functions may start a message loop and process
// message recursively, so disable recursive task processing.
// TODO(thestig): See above comment. SetNestableTasksAllowed(false) needs to
// be called on the same thread as the previous call. See
// http://crbug.com/73466
// MessageLoop::current()->SetNestableTasksAllowed(false);
// We can't use OnFailure() here since owner_ may not support notifications.
// PrintJob will create the new PrintedDocument.
owner_->message_loop()->PostTask(
FROM_HERE,
base::Bind(&PrintJobWorkerOwner::GetSettingsDone,
make_scoped_refptr(owner_), printing_context_->settings(),
result));
}
void PrintJobWorker::GetSettingsWithUI(
scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
int document_page_count,
bool has_selection) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
gfx::NativeView parent_view = web_contents_observer->GetParentView();
if (!parent_view) {
GetSettingsWithUIDone(printing::PrintingContext::FAILED);
return;
}
printing_context_->AskUserForSettings(
parent_view, document_page_count, has_selection,
base::Bind(&PrintJobWorker::GetSettingsWithUIDone,
base::Unretained(this)));
}
void PrintJobWorker::GetSettingsWithUIDone(PrintingContext::Result result) {
message_loop()->PostTask(
FROM_HERE,
base::Bind(&HoldRefCallback, make_scoped_refptr(owner_),
base::Bind(&PrintJobWorker::GetSettingsDone,
base::Unretained(this), result)));
}
void PrintJobWorker::UseDefaultSettings() {
PrintingContext::Result result = printing_context_->UseDefaultSettings();
GetSettingsDone(result);
}
void PrintJobWorker::StartPrinting(PrintedDocument* new_document) {
DCHECK_EQ(message_loop(), base::MessageLoop::current());
DCHECK_EQ(page_number_, PageNumber::npos());
DCHECK_EQ(document_, new_document);
DCHECK(document_.get());
if (!document_.get() || page_number_ != PageNumber::npos() ||
document_.get() != new_document) {
return;
}
base::string16 document_name =
printing::SimplifyDocumentTitle(document_->name());
if (document_name.empty()) {
// document_name = printing::SimplifyDocumentTitle(
// l10n_util::GetStringUTF16(IDS_DEFAULT_PRINT_DOCUMENT_TITLE));
}
PrintingContext::Result result =
printing_context_->NewDocument(document_name);
if (result != PrintingContext::OK) {
OnFailure();
return;
}
// Try to print already cached data. It may already have been generated for
// the print preview.
OnNewPage();
// Don't touch this anymore since the instance could be destroyed. It happens
// if all the pages are printed a one sweep and the client doesn't have a
// handle to us anymore. There's a timing issue involved between the worker
// thread and the UI thread. Take no chance.
}
void PrintJobWorker::OnDocumentChanged(PrintedDocument* new_document) {
DCHECK_EQ(message_loop(), base::MessageLoop::current());
DCHECK_EQ(page_number_, PageNumber::npos());
if (page_number_ != PageNumber::npos())
return;
document_ = new_document;
}
void PrintJobWorker::OnNewPage() {
if (!document_.get()) // Spurious message.
return;
// message_loop() could return NULL when the print job is cancelled.
DCHECK_EQ(message_loop(), base::MessageLoop::current());
if (page_number_ == PageNumber::npos()) {
// Find first page to print.
int page_count = document_->page_count();
if (!page_count) {
// We still don't know how many pages the document contains. We can't
// start to print the document yet since the header/footer may refer to
// the document's page count.
return;
}
// We have enough information to initialize page_number_.
page_number_.Init(document_->settings(), page_count);
if (destination_.get() != NULL)
destination_->SetPageCount(page_count);
}
DCHECK_NE(page_number_, PageNumber::npos());
while (true) {
// Is the page available?
scoped_refptr<PrintedPage> page;
if (!document_->GetPage(page_number_.ToInt(), &page)) {
// We need to wait for the page to be available.
base::MessageLoop::current()->PostDelayedTask(
FROM_HERE,
base::Bind(&PrintJobWorker::OnNewPage, weak_factory_.GetWeakPtr()),
base::TimeDelta::FromMilliseconds(500));
break;
}
// The page is there, print it.
SpoolPage(page.get());
++page_number_;
if (page_number_ == PageNumber::npos()) {
OnDocumentDone();
// Don't touch this anymore since the instance could be destroyed.
break;
}
}
}
void PrintJobWorker::Cancel() {
// This is the only function that can be called from any thread.
printing_context_->Cancel();
// Cannot touch any member variable since we don't know in which thread
// context we run.
}
void PrintJobWorker::OnDocumentDone() {
DCHECK_EQ(message_loop(), base::MessageLoop::current());
DCHECK_EQ(page_number_, PageNumber::npos());
DCHECK(document_.get());
if (printing_context_->DocumentDone() != PrintingContext::OK) {
OnFailure();
return;
}
owner_->message_loop()->PostTask(
FROM_HERE, base::Bind(NotificationCallback, make_scoped_refptr(owner_),
JobEventDetails::DOC_DONE, document_,
scoped_refptr<PrintedPage>()));
// Makes sure the variables are reinitialized.
document_ = NULL;
}
void PrintJobWorker::SpoolPage(PrintedPage* page) {
DCHECK_EQ(message_loop(), base::MessageLoop::current());
DCHECK_NE(page_number_, PageNumber::npos());
// Signal everyone that the page is about to be printed.
owner_->message_loop()->PostTask(
FROM_HERE, base::Bind(NotificationCallback, make_scoped_refptr(owner_),
JobEventDetails::NEW_PAGE, document_,
make_scoped_refptr(page)));
// Preprocess.
if (printing_context_->NewPage() != PrintingContext::OK) {
OnFailure();
return;
}
if (destination_.get() != NULL) {
std::vector<uint8> metabytes(page->metafile()->GetDataSize());
bool success = page->metafile()->GetData(
reinterpret_cast<void*>(&metabytes[0]), metabytes.size());
DCHECK(success) << "Failed to get metafile data.";
destination_->SetPageContent(
page->page_number(),
reinterpret_cast<void*>(&metabytes[0]),
metabytes.size());
return;
}
// Actual printing.
#if defined(OS_WIN) || defined(OS_MACOSX)
document_->RenderPrintedPage(*page, printing_context_->context());
#elif defined(OS_POSIX)
document_->RenderPrintedPage(*page, printing_context_.get());
#endif
// Postprocess.
if (printing_context_->PageDone() != PrintingContext::OK) {
OnFailure();
return;
}
// Signal everyone that the page is printed.
owner_->message_loop()->PostTask(
FROM_HERE,
base::Bind(NotificationCallback, make_scoped_refptr(owner_),
JobEventDetails::PAGE_DONE, document_,
make_scoped_refptr(page)));
}
void PrintJobWorker::OnFailure() {
DCHECK_EQ(message_loop(), base::MessageLoop::current());
// We may loose our last reference by broadcasting the FAILED event.
scoped_refptr<PrintJobWorkerOwner> handle(owner_);
owner_->message_loop()->PostTask(
FROM_HERE, base::Bind(NotificationCallback, make_scoped_refptr(owner_),
JobEventDetails::FAILED, document_,
scoped_refptr<PrintedPage>()));
Cancel();
// Makes sure the variables are reinitialized.
document_ = NULL;
page_number_ = PageNumber::npos();
}
} // namespace printing

View file

@ -0,0 +1,145 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_H_
#define CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_H_
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread.h"
#include "printing/page_number.h"
#include "printing/print_destination_interface.h"
#include "printing/printing_context.h"
#include "printing/print_job_constants.h"
class PrintingUIWebContentsObserver;
namespace base {
class DictionaryValue;
}
namespace printing {
class PrintedDocument;
class PrintedPage;
class PrintJob;
class PrintJobWorkerOwner;
// Worker thread code. It manages the PrintingContext, which can be blocking
// and/or run a message loop. This is the object that generates most
// NOTIFY_PRINT_JOB_EVENT notifications, but they are generated through a
// NotificationTask task to be executed from the right thread, the UI thread.
// PrintJob always outlives its worker instance.
class PrintJobWorker : public base::Thread {
public:
explicit PrintJobWorker(PrintJobWorkerOwner* owner);
virtual ~PrintJobWorker();
void SetNewOwner(PrintJobWorkerOwner* new_owner);
// Set a destination for print.
// This supercedes the document's rendering destination.
void SetPrintDestination(PrintDestinationInterface* destination);
// Initializes the print settings. If |ask_user_for_settings| is true, a
// Print... dialog box will be shown to ask the user his preference.
void GetSettings(
bool ask_user_for_settings,
scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
int document_page_count,
bool has_selection,
MarginType margin_type);
// Set the new print settings. This function takes ownership of
// |new_settings|.
void SetSettings(const base::DictionaryValue* const new_settings);
// Starts the printing loop. Every pages are printed as soon as the data is
// available. Makes sure the new_document is the right one.
void StartPrinting(PrintedDocument* new_document);
// Updates the printed document.
void OnDocumentChanged(PrintedDocument* new_document);
// Dequeues waiting pages. Called when PrintJob receives a
// NOTIFY_PRINTED_DOCUMENT_UPDATED notification. It's time to look again if
// the next page can be printed.
void OnNewPage();
// This is the only function that can be called in a thread.
void Cancel();
protected:
// Retrieves the context for testing only.
PrintingContext* printing_context() { return printing_context_.get(); }
private:
// The shared NotificationService service can only be accessed from the UI
// thread, so this class encloses the necessary information to send the
// notification from the right thread. Most NOTIFY_PRINT_JOB_EVENT
// notifications are sent this way, except USER_INIT_DONE, USER_INIT_CANCELED
// and DEFAULT_INIT_DONE. These three are sent through PrintJob::InitDone().
class NotificationTask;
// Renders a page in the printer.
void SpoolPage(PrintedPage* page);
// Closes the job since spooling is done.
void OnDocumentDone();
// Discards the current document, the current page and cancels the printing
// context.
void OnFailure();
// Asks the user for print settings. Must be called on the UI thread.
// Required on Mac and Linux. Windows can display UI from non-main threads,
// but sticks with this for consistency.
void GetSettingsWithUI(
scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
int document_page_count,
bool has_selection);
// The callback used by PrintingContext::GetSettingsWithUI() to notify this
// object that the print settings are set. This is needed in order to bounce
// back into the IO thread for GetSettingsDone().
void GetSettingsWithUIDone(PrintingContext::Result result);
// Called on the UI thread to update the print settings. This function takes
// the ownership of |new_settings|.
void UpdatePrintSettings(const base::DictionaryValue* const new_settings);
// Reports settings back to owner_.
void GetSettingsDone(PrintingContext::Result result);
// Use the default settings. When using GTK+ or Mac, this can still end up
// displaying a dialog. So this needs to happen from the UI thread on these
// systems.
void UseDefaultSettings();
// Information about the printer setting.
scoped_ptr<PrintingContext> printing_context_;
// The printed document. Only has read-only access.
scoped_refptr<PrintedDocument> document_;
// The print destination, may be NULL.
scoped_refptr<PrintDestinationInterface> destination_;
// The print job owning this worker thread. It is guaranteed to outlive this
// object.
PrintJobWorkerOwner* owner_;
// Current page number to print.
PageNumber page_number_;
// Used to generate a WeakPtr for callbacks.
base::WeakPtrFactory<PrintJobWorker> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(PrintJobWorker);
};
} // namespace printing
#endif // CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_H_

View file

@ -0,0 +1,50 @@
// Copyright (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 CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_OWNER_H__
#define CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_OWNER_H__
#include "base/memory/ref_counted.h"
#include "printing/printing_context.h"
namespace base {
class MessageLoop;
}
namespace printing {
class PrintJobWorker;
class PrintSettings;
class PrintJobWorkerOwner
: public base::RefCountedThreadSafe<PrintJobWorkerOwner> {
public:
// Finishes the initialization began by PrintJobWorker::GetSettings().
// Creates a new PrintedDocument if necessary. Solely meant to be called by
// PrintJobWorker.
virtual void GetSettingsDone(const PrintSettings& new_settings,
PrintingContext::Result result) = 0;
// Detach the PrintJobWorker associated to this object.
virtual PrintJobWorker* DetachWorker(PrintJobWorkerOwner* new_owner) = 0;
// Retrieves the message loop that is expected to process GetSettingsDone.
virtual base::MessageLoop* message_loop() = 0;
// Access the current settings.
virtual const PrintSettings& settings() const = 0;
// Cookie uniquely identifying the PrintedDocument and/or loaded settings.
virtual int cookie() const = 0;
protected:
friend class base::RefCountedThreadSafe<PrintJobWorkerOwner>;
virtual ~PrintJobWorkerOwner() {}
};
} // namespace printing
#endif // CHROME_BROWSER_PRINTING_PRINT_JOB_WORKER_OWNER_H__

View file

@ -0,0 +1,509 @@
// 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 "chrome/browser/printing/print_view_manager_base.h"
#include <map>
#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/browser/profiles/profile.h"
#include "chrome/browser/ui/simple_message_box.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 "grit/generated_resources.h"
#include "printing/metafile_impl.h"
#include "printing/printed_document.h"
#include "ui/base/l10n/l10n_util.h"
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_ = true;
}
PrintViewManagerBase::~PrintViewManagerBase() {
ReleasePrinterQuery();
DisconnectFromCurrentPrintJob();
}
bool PrintViewManagerBase::PrintNow(bool silent, bool print_background) {
return PrintNowInternal(new PrintMsg_PrintPages(
routing_id(), silent, print_background));
}
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());
}
}
base::string16 PrintViewManagerBase::RenderSourceName() {
base::string16 name(web_contents()->GetTitle());
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);
int raster_size = std::min(params.page_size.GetArea(),
kMaxRasterSizeInPixels);
if (big_emf) {
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::OnShowInvalidPrinterSettingsError() {
LOG(ERROR) << "Invalid printer settings";
}
void PrintViewManagerBase::DidStartLoading(
content::RenderViewHost* render_view_host) {
}
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_HANDLER(PrintHostMsg_ShowInvalidPrinterSettingsError,
OnShowInvalidPrinterSettingsError);
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,164 @@
// 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 CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_BASE_H_
#define CHROME_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(bool silent, bool print_background);
// PrintedPagesSource implementation.
virtual base::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);
void OnShowInvalidPrinterSettingsError();
// 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.
bool printing_enabled_;
scoped_refptr<printing::PrintQueriesQueue> queue_;
DISALLOW_COPY_AND_ASSIGN(PrintViewManagerBase);
};
} // namespace printing
#endif // CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_BASE_H_

View file

@ -0,0 +1,48 @@
// 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 "chrome/browser/printing/print_view_manager_basic.h"
#if defined(OS_ANDROID)
#include "base/file_descriptor_posix.h"
#include "chrome/common/print_messages.h"
#include "printing/printing_context_android.h"
#endif
DEFINE_WEB_CONTENTS_USER_DATA_KEY(printing::PrintViewManagerBasic);
namespace printing {
PrintViewManagerBasic::PrintViewManagerBasic(content::WebContents* web_contents)
: PrintViewManagerBase(web_contents) {
}
PrintViewManagerBasic::~PrintViewManagerBasic() {
}
#if defined(OS_ANDROID)
void PrintViewManagerBasic::RenderProcessGone(base::TerminationStatus status) {
PrintingContextAndroid::PdfWritingDone(file_descriptor_.fd, false);
file_descriptor_ = base::FileDescriptor(-1, false);
PrintViewManagerBase::RenderProcessGone(status);
}
void PrintViewManagerBasic::OnPrintingFailed(int cookie) {
PrintingContextAndroid::PdfWritingDone(file_descriptor_.fd, false);
file_descriptor_ = base::FileDescriptor(-1, false);
PrintViewManagerBase::OnPrintingFailed(cookie);
}
bool PrintViewManagerBasic::OnMessageReceived(const IPC::Message& message) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(PrintViewManagerBasic, message)
IPC_MESSAGE_HANDLER(PrintHostMsg_PrintingFailed, OnPrintingFailed)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled ? true : PrintViewManagerBase::OnMessageReceived(message);
}
#endif
} // namespace printing

View file

@ -0,0 +1,57 @@
// 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 CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_BASIC_H_
#define CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_BASIC_H_
#include "chrome/browser/printing/print_view_manager_base.h"
#include "content/public/browser/web_contents_user_data.h"
#if defined(OS_ANDROID)
#include "base/file_descriptor_posix.h"
#endif
namespace printing {
// Manages the print commands for a WebContents - basic version.
class PrintViewManagerBasic
: public PrintViewManagerBase,
public content::WebContentsUserData<PrintViewManagerBasic> {
public:
virtual ~PrintViewManagerBasic();
#if defined(OS_ANDROID)
// Sets the file descriptor into which the PDF will be written.
void set_file_descriptor(const base::FileDescriptor& file_descriptor) {
file_descriptor_ = file_descriptor;
}
// Gets the file descriptor into which the PDF will be written.
base::FileDescriptor file_descriptor() const { return file_descriptor_; }
// content::WebContentsObserver implementation.
// 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;
#endif
private:
explicit PrintViewManagerBasic(content::WebContents* web_contents);
friend class content::WebContentsUserData<PrintViewManagerBasic>;
#if defined(OS_ANDROID)
virtual void OnPrintingFailed(int cookie) OVERRIDE;
// The file descriptor into which the PDF of the page will be written.
base::FileDescriptor file_descriptor_;
#endif
DISALLOW_COPY_AND_ASSIGN(PrintViewManagerBasic);
};
} // namespace printing
#endif // CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_BASIC_H_

View file

@ -0,0 +1,23 @@
// Copyright (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 CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_OBSERVER_H_
#define CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_OBSERVER_H_
namespace printing {
// An interface the PrintViewManager uses to notify an observer when the print
// dialog is shown. Register the observer via PrintViewManager::set_observer.
class PrintViewManagerObserver {
public:
// Notifies the observer that the print dialog was shown.
virtual void OnPrintDialogShown() = 0;
protected:
virtual ~PrintViewManagerObserver() {}
};
} // namespace printing
#endif // CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_OBSERVER_H_

View file

@ -0,0 +1,143 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/printing/printer_query.h"
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/message_loop/message_loop.h"
#include "base/threading/thread_restrictions.h"
#include "base/values.h"
#include "chrome/browser/printing/print_job_worker.h"
#include "chrome/browser/printing/printing_ui_web_contents_observer.h"
namespace printing {
PrinterQuery::PrinterQuery()
: io_message_loop_(base::MessageLoop::current()),
worker_(new PrintJobWorker(this)),
is_print_dialog_box_shown_(false),
cookie_(PrintSettings::NewCookie()),
last_status_(PrintingContext::FAILED) {
DCHECK(base::MessageLoopForIO::IsCurrent());
}
PrinterQuery::~PrinterQuery() {
// The job should be finished (or at least canceled) when it is destroyed.
DCHECK(!is_print_dialog_box_shown_);
// If this fires, it is that this pending printer context has leaked.
DCHECK(!worker_.get());
}
void PrinterQuery::GetSettingsDone(const PrintSettings& new_settings,
PrintingContext::Result result) {
is_print_dialog_box_shown_ = false;
last_status_ = result;
if (result != PrintingContext::FAILED) {
settings_ = new_settings;
cookie_ = PrintSettings::NewCookie();
} else {
// Failure.
cookie_ = 0;
}
if (!callback_.is_null()) {
// This may cause reentrancy like to call StopWorker().
callback_.Run();
callback_.Reset();
}
}
PrintJobWorker* PrinterQuery::DetachWorker(PrintJobWorkerOwner* new_owner) {
DCHECK(callback_.is_null());
DCHECK(worker_.get());
worker_->SetNewOwner(new_owner);
return worker_.release();
}
base::MessageLoop* PrinterQuery::message_loop() {
return io_message_loop_;
}
const PrintSettings& PrinterQuery::settings() const {
return settings_;
}
int PrinterQuery::cookie() const {
return cookie_;
}
void PrinterQuery::GetSettings(
GetSettingsAskParam ask_user_for_settings,
scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
int expected_page_count,
bool has_selection,
MarginType margin_type,
const base::Closure& callback) {
DCHECK_EQ(io_message_loop_, base::MessageLoop::current());
DCHECK(!is_print_dialog_box_shown_);
StartWorker(callback);
// Real work is done in PrintJobWorker::GetSettings().
is_print_dialog_box_shown_ = ask_user_for_settings == ASK_USER;
worker_->message_loop()->PostTask(
FROM_HERE,
base::Bind(&PrintJobWorker::GetSettings,
base::Unretained(worker_.get()),
is_print_dialog_box_shown_,
base::Passed(&web_contents_observer),
expected_page_count,
has_selection,
margin_type));
}
void PrinterQuery::SetSettings(const base::DictionaryValue& new_settings,
const base::Closure& callback) {
StartWorker(callback);
worker_->message_loop()->PostTask(
FROM_HERE,
base::Bind(&PrintJobWorker::SetSettings,
base::Unretained(worker_.get()),
new_settings.DeepCopy()));
}
void PrinterQuery::SetWorkerDestination(
PrintDestinationInterface* destination) {
worker_->SetPrintDestination(destination);
}
void PrinterQuery::StartWorker(const base::Closure& callback) {
DCHECK(callback_.is_null());
DCHECK(worker_.get());
// Lazily create the worker thread. There is one worker thread per print job.
if (!worker_->message_loop())
worker_->Start();
callback_ = callback;
}
void PrinterQuery::StopWorker() {
if (worker_.get()) {
// http://crbug.com/66082: We're blocking on the PrinterQuery's worker
// thread. It's not clear to me if this may result in blocking the current
// thread for an unacceptable time. We should probably fix it.
base::ThreadRestrictions::ScopedAllowIO allow_io;
worker_->Stop();
worker_.reset();
}
}
bool PrinterQuery::is_callback_pending() const {
return !callback_.is_null();
}
bool PrinterQuery::is_valid() const {
return worker_.get() != NULL;
}
} // namespace printing

View file

@ -0,0 +1,110 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PRINTING_PRINTER_QUERY_H_
#define CHROME_BROWSER_PRINTING_PRINTER_QUERY_H_
#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/printing/print_job_worker_owner.h"
#include "printing/print_job_constants.h"
class PrintingUIWebContentsObserver;
namespace base {
class DictionaryValue;
class MessageLoop;
}
namespace printing {
class PrintDestinationInterface;
class PrintJobWorker;
// Query the printer for settings.
class PrinterQuery : public PrintJobWorkerOwner {
public:
// GetSettings() UI parameter.
enum GetSettingsAskParam {
DEFAULTS,
ASK_USER,
};
PrinterQuery();
// PrintJobWorkerOwner implementation.
virtual void GetSettingsDone(const PrintSettings& new_settings,
PrintingContext::Result result) OVERRIDE;
virtual PrintJobWorker* DetachWorker(PrintJobWorkerOwner* new_owner) OVERRIDE;
virtual base::MessageLoop* message_loop() OVERRIDE;
virtual const PrintSettings& settings() const OVERRIDE;
virtual int cookie() const OVERRIDE;
// Initializes the printing context. It is fine to call this function multiple
// times to reinitialize the settings. |web_contents_observer| can be queried
// to find the owner of the print setting dialog box. It is unused when
// |ask_for_user_settings| is DEFAULTS.
void GetSettings(
GetSettingsAskParam ask_user_for_settings,
scoped_ptr<PrintingUIWebContentsObserver> web_contents_observer,
int expected_page_count,
bool has_selection,
MarginType margin_type,
const base::Closure& callback);
// Updates the current settings with |new_settings| dictionary values.
void SetSettings(const base::DictionaryValue& new_settings,
const base::Closure& callback);
// Set a destination for the worker.
void SetWorkerDestination(PrintDestinationInterface* destination);
// Stops the worker thread since the client is done with this object.
void StopWorker();
// Returns true if a GetSettings() call is pending completion.
bool is_callback_pending() const;
PrintingContext::Result last_status() const { return last_status_; }
// Returns if a worker thread is still associated to this instance.
bool is_valid() const;
private:
virtual ~PrinterQuery();
// Lazy create the worker thread. There is one worker thread per print job.
void StartWorker(const base::Closure& callback);
// Main message loop reference. Used to send notifications in the right
// thread.
base::MessageLoop* const io_message_loop_;
// All the UI is done in a worker thread because many Win32 print functions
// are blocking and enters a message loop without your consent. There is one
// worker thread per print job.
scoped_ptr<PrintJobWorker> worker_;
// Cache of the print context settings for access in the UI thread.
PrintSettings settings_;
// Is the Print... dialog box currently shown.
bool is_print_dialog_box_shown_;
// Cookie that make this instance unique.
int cookie_;
// Results from the last GetSettingsDone() callback.
PrintingContext::Result last_status_;
// Callback waiting to be run.
base::Closure callback_;
DISALLOW_COPY_AND_ASSIGN(PrinterQuery);
};
} // namespace printing
#endif // CHROME_BROWSER_PRINTING_PRINTER_QUERY_H_

View file

@ -0,0 +1,234 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/printing/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/browser/printing/printing_ui_web_contents_observer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_io_data.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"
using content::BrowserThread;
namespace {
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->title = settings.title();
params->url = settings.url();
}
} // namespace
PrintingMessageFilter::PrintingMessageFilter(int render_process_id)
: BrowserMessageFilter(PrintMsgStart),
render_process_id_(render_process_id),
queue_(g_browser_process->print_job_manager()->queue()) {
DCHECK(queue_);
}
PrintingMessageFilter::~PrintingMessageFilter() {
}
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
IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_GetDefaultPrintSettings,
OnGetDefaultPrintSettings)
IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_ScriptedPrint, OnScriptedPrint)
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
content::WebContents* PrintingMessageFilter::GetWebContentsForRenderView(
int render_view_id) {
DCHECK_CURRENTLY_ON(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_CURRENTLY_ON(BrowserThread::UI);
content::WebContents* wc = GetWebContentsForRenderView(render_view_id);
if (wc) {
scoped_ptr<PrintingUIWebContentsObserver> wc_observer(
new PrintingUIWebContentsObserver(wc));
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&printing::PrinterQuery::GetSettings, printer_query,
params.ask_user_for_settings, base::Passed(&wc_observer),
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_CURRENTLY_ON(BrowserThread::IO);
printer_query->GetSettingsDone(printing::PrintSettings(),
printing::PrintingContext::FAILED);
callback.Run();
}
void PrintingMessageFilter::OnGetDefaultPrintSettings(IPC::Message* reply_msg) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
scoped_refptr<printing::PrinterQuery> printer_query;
if (false) {
// Reply with NULL query.
OnGetDefaultPrintSettingsReply(printer_query, reply_msg);
return;
}
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 (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) {
queue_->QueuePrinterQuery(printer_query.get());
} else {
printer_query->StopWorker();
}
}

View file

@ -0,0 +1,97 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PRINTING_PRINTING_MESSAGE_FILTER_H_
#define CHROME_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 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
// 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);
// 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);
const int render_process_id_;
scoped_refptr<printing::PrintQueriesQueue> queue_;
DISALLOW_COPY_AND_ASSIGN(PrintingMessageFilter);
};
#endif // CHROME_BROWSER_PRINTING_PRINTING_MESSAGE_FILTER_H_

View file

@ -0,0 +1,19 @@
// 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 "chrome/browser/printing/printing_ui_web_contents_observer.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
PrintingUIWebContentsObserver::PrintingUIWebContentsObserver(
content::WebContents* web_contents)
: content::WebContentsObserver(web_contents) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
}
gfx::NativeView PrintingUIWebContentsObserver::GetParentView() {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
return web_contents() ? web_contents()->GetNativeView() : NULL;
}

View file

@ -0,0 +1,25 @@
// 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 CHROME_BROWSER_PRINTING_PRINTING_UI_WEB_CONTENTS_OBSERVER_H_
#define CHROME_BROWSER_PRINTING_PRINTING_UI_WEB_CONTENTS_OBSERVER_H_
#include "base/basictypes.h"
#include "content/public/browser/web_contents_observer.h"
#include "ui/gfx/native_widget_types.h"
// Wrapper used to keep track of the lifetime of a WebContents.
// Lives on the UI thread.
class PrintingUIWebContentsObserver : public content::WebContentsObserver {
public:
explicit PrintingUIWebContentsObserver(content::WebContents* web_contents);
// Return the parent NativeView of the observed WebContents.
gfx::NativeView GetParentView();
private:
DISALLOW_COPY_AND_ASSIGN(PrintingUIWebContentsObserver);
};
#endif // CHROME_BROWSER_PRINTING_PRINTING_UI_WEB_CONTENTS_OBSERVER_H_

View file

View file

@ -0,0 +1,60 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/common/print_messages.h"
#include "base/basictypes.h"
#include "base/strings/string16.h"
#include "ui/gfx/size.h"
PrintMsg_Print_Params::PrintMsg_Print_Params()
: page_size(),
content_size(),
printable_area(),
margin_top(0),
margin_left(0),
dpi(0),
min_shrink(0),
max_shrink(0),
desired_dpi(0),
document_cookie(0),
selection_only(false),
supports_alpha_blend(false),
print_scaling_option(blink::WebPrintScalingOptionSourceSize),
title(),
url(),
should_print_backgrounds(false) {
}
PrintMsg_Print_Params::~PrintMsg_Print_Params() {}
void PrintMsg_Print_Params::Reset() {
page_size = gfx::Size();
content_size = gfx::Size();
printable_area = gfx::Rect();
margin_top = 0;
margin_left = 0;
dpi = 0;
min_shrink = 0;
max_shrink = 0;
desired_dpi = 0;
document_cookie = 0;
selection_only = false;
supports_alpha_blend = false;
print_scaling_option = blink::WebPrintScalingOptionSourceSize;
title.clear();
url.clear();
should_print_backgrounds = false;
}
PrintMsg_PrintPages_Params::PrintMsg_PrintPages_Params()
: pages() {
}
PrintMsg_PrintPages_Params::~PrintMsg_PrintPages_Params() {}
void PrintMsg_PrintPages_Params::Reset() {
params.Reset();
pages = std::vector<int>();
}

View file

@ -0,0 +1,241 @@
// 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.
// IPC messages for printing.
// Multiply-included message file, hence no include guard.
#include <string>
#include <vector>
#include "base/memory/shared_memory.h"
#include "base/values.h"
#include "ipc/ipc_message_macros.h"
#include "printing/page_size_margins.h"
#include "printing/print_job_constants.h"
#include "third_party/WebKit/public/web/WebPrintScalingOption.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/rect.h"
#ifndef CHROME_COMMON_PRINT_MESSAGES_H_
#define CHROME_COMMON_PRINT_MESSAGES_H_
struct PrintMsg_Print_Params {
PrintMsg_Print_Params();
~PrintMsg_Print_Params();
// Resets the members of the struct to 0.
void Reset();
gfx::Size page_size;
gfx::Size content_size;
gfx::Rect printable_area;
int margin_top;
int margin_left;
double dpi;
double min_shrink;
double max_shrink;
int desired_dpi;
int document_cookie;
bool selection_only;
bool supports_alpha_blend;
blink::WebPrintScalingOption print_scaling_option;
base::string16 title;
base::string16 url;
bool should_print_backgrounds;
};
struct PrintMsg_PrintPages_Params {
PrintMsg_PrintPages_Params();
~PrintMsg_PrintPages_Params();
// Resets the members of the struct to 0.
void Reset();
PrintMsg_Print_Params params;
std::vector<int> pages;
};
#endif // CHROME_COMMON_PRINT_MESSAGES_H_
#define IPC_MESSAGE_START PrintMsgStart
IPC_ENUM_TRAITS_MAX_VALUE(printing::MarginType,
printing::MARGIN_TYPE_LAST)
IPC_ENUM_TRAITS_MAX_VALUE(blink::WebPrintScalingOption,
blink::WebPrintScalingOptionLast)
// Parameters for a render request.
IPC_STRUCT_TRAITS_BEGIN(PrintMsg_Print_Params)
// Physical size of the page, including non-printable margins,
// in pixels according to dpi.
IPC_STRUCT_TRAITS_MEMBER(page_size)
// In pixels according to dpi_x and dpi_y.
IPC_STRUCT_TRAITS_MEMBER(content_size)
// Physical printable area of the page in pixels according to dpi.
IPC_STRUCT_TRAITS_MEMBER(printable_area)
// The y-offset of the printable area, in pixels according to dpi.
IPC_STRUCT_TRAITS_MEMBER(margin_top)
// The x-offset of the printable area, in pixels according to dpi.
IPC_STRUCT_TRAITS_MEMBER(margin_left)
// Specifies dots per inch.
IPC_STRUCT_TRAITS_MEMBER(dpi)
// Minimum shrink factor. See PrintSettings::min_shrink for more information.
IPC_STRUCT_TRAITS_MEMBER(min_shrink)
// Maximum shrink factor. See PrintSettings::max_shrink for more information.
IPC_STRUCT_TRAITS_MEMBER(max_shrink)
// Desired apparent dpi on paper.
IPC_STRUCT_TRAITS_MEMBER(desired_dpi)
// Cookie for the document to ensure correctness.
IPC_STRUCT_TRAITS_MEMBER(document_cookie)
// Should only print currently selected text.
IPC_STRUCT_TRAITS_MEMBER(selection_only)
// Does the printer support alpha blending?
IPC_STRUCT_TRAITS_MEMBER(supports_alpha_blend)
// Specifies the page scaling option for preview printing.
IPC_STRUCT_TRAITS_MEMBER(print_scaling_option)
// Title string to be printed as header if requested by the user.
IPC_STRUCT_TRAITS_MEMBER(title)
// URL string to be printed as footer if requested by the user.
IPC_STRUCT_TRAITS_MEMBER(url)
// True if print backgrounds is requested by the user.
IPC_STRUCT_TRAITS_MEMBER(should_print_backgrounds)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_BEGIN(PrintMsg_PrintPage_Params)
// Parameters to render the page as a printed page. It must always be the same
// value for all the document.
IPC_STRUCT_MEMBER(PrintMsg_Print_Params, params)
// The page number is the indicator of the square that should be rendered
// according to the layout specified in PrintMsg_Print_Params.
IPC_STRUCT_MEMBER(int, page_number)
IPC_STRUCT_END()
IPC_STRUCT_TRAITS_BEGIN(printing::PageSizeMargins)
IPC_STRUCT_TRAITS_MEMBER(content_width)
IPC_STRUCT_TRAITS_MEMBER(content_height)
IPC_STRUCT_TRAITS_MEMBER(margin_left)
IPC_STRUCT_TRAITS_MEMBER(margin_right)
IPC_STRUCT_TRAITS_MEMBER(margin_top)
IPC_STRUCT_TRAITS_MEMBER(margin_bottom)
IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(PrintMsg_PrintPages_Params)
// Parameters to render the page as a printed page. It must always be the same
// value for all the document.
IPC_STRUCT_TRAITS_MEMBER(params)
// If empty, this means a request to render all the printed pages.
IPC_STRUCT_TRAITS_MEMBER(pages)
IPC_STRUCT_TRAITS_END()
// Parameters to describe a rendered page.
IPC_STRUCT_BEGIN(PrintHostMsg_DidPrintPage_Params)
// A shared memory handle to the EMF data. This data can be quite large so a
// memory map needs to be used.
IPC_STRUCT_MEMBER(base::SharedMemoryHandle, metafile_data_handle)
// Size of the metafile data.
IPC_STRUCT_MEMBER(uint32, data_size)
// Cookie for the document to ensure correctness.
IPC_STRUCT_MEMBER(int, document_cookie)
// Page number.
IPC_STRUCT_MEMBER(int, page_number)
// Shrink factor used to render this page.
IPC_STRUCT_MEMBER(double, actual_shrink)
// The size of the page the page author specified.
IPC_STRUCT_MEMBER(gfx::Size, page_size)
// The printable area the page author specified.
IPC_STRUCT_MEMBER(gfx::Rect, content_area)
IPC_STRUCT_END()
// Parameters for the IPC message ViewHostMsg_ScriptedPrint
IPC_STRUCT_BEGIN(PrintHostMsg_ScriptedPrint_Params)
IPC_STRUCT_MEMBER(int, cookie)
IPC_STRUCT_MEMBER(int, expected_pages_count)
IPC_STRUCT_MEMBER(bool, has_selection)
IPC_STRUCT_MEMBER(printing::MarginType, margin_type)
IPC_STRUCT_END()
// Messages sent from the browser to the renderer.
// Tells the render view to switch the CSS to print media type, renders every
// requested pages and switch back the CSS to display media type.
IPC_MESSAGE_ROUTED2(PrintMsg_PrintPages,
bool /* silent print */,
bool /* print page's background */)
// Tells the render view that printing is done so it can clean up.
IPC_MESSAGE_ROUTED1(PrintMsg_PrintingDone,
bool /* success */)
// Messages sent from the renderer to the browser.
#if defined(OS_WIN)
// Duplicates a shared memory handle from the renderer to the browser. Then
// the renderer can flush the handle.
IPC_SYNC_MESSAGE_ROUTED1_1(PrintHostMsg_DuplicateSection,
base::SharedMemoryHandle /* renderer handle */,
base::SharedMemoryHandle /* browser handle */)
#endif
// Tells the browser that the renderer is done calculating the number of
// rendered pages according to the specified settings.
IPC_MESSAGE_ROUTED2(PrintHostMsg_DidGetPrintedPagesCount,
int /* rendered document cookie */,
int /* number of rendered pages */)
// Sends the document cookie of the current printer query to the browser.
IPC_MESSAGE_ROUTED1(PrintHostMsg_DidGetDocumentCookie,
int /* rendered document cookie */)
// Tells the browser that the print dialog has been shown.
IPC_MESSAGE_ROUTED0(PrintHostMsg_DidShowPrintDialog)
// Sends back to the browser the rendered "printed page" that was requested by
// a ViewMsg_PrintPage message or from scripted printing. The memory handle in
// this message is already valid in the browser process.
IPC_MESSAGE_ROUTED1(PrintHostMsg_DidPrintPage,
PrintHostMsg_DidPrintPage_Params /* page content */)
// The renderer wants to know the default print settings.
IPC_SYNC_MESSAGE_ROUTED0_1(PrintHostMsg_GetDefaultPrintSettings,
PrintMsg_Print_Params /* default_settings */)
// It's the renderer that controls the printing process when it is generated
// by javascript. This step is about showing UI to the user to select the
// final print settings. The output parameter is the same as
// ViewMsg_PrintPages which is executed implicitly.
IPC_SYNC_MESSAGE_ROUTED1_1(PrintHostMsg_ScriptedPrint,
PrintHostMsg_ScriptedPrint_Params,
PrintMsg_PrintPages_Params
/* settings chosen by the user*/)
// This is sent when there are invalid printer settings.
IPC_MESSAGE_ROUTED0(PrintHostMsg_ShowInvalidPrinterSettingsError)
// Tell the browser printing failed.
IPC_MESSAGE_ROUTED1(PrintHostMsg_PrintingFailed,
int /* document cookie */)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,218 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_RENDERER_PRINTING_PRINT_WEB_VIEW_HELPER_H_
#define CHROME_RENDERER_PRINTING_PRINT_WEB_VIEW_HELPER_H_
#include <vector>
#include "base/memory/scoped_ptr.h"
#include "base/memory/shared_memory.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "content/public/renderer/render_view_observer.h"
#include "content/public/renderer/render_view_observer_tracker.h"
#include "printing/metafile_impl.h"
#include "third_party/WebKit/public/platform/WebCanvas.h"
#include "third_party/WebKit/public/web/WebNode.h"
#include "third_party/WebKit/public/web/WebPrintParams.h"
#include "ui/gfx/size.h"
struct PrintMsg_Print_Params;
struct PrintMsg_PrintPage_Params;
struct PrintMsg_PrintPages_Params;
namespace base {
class DictionaryValue;
}
namespace blink {
class WebFrame;
class WebView;
}
namespace printing {
struct PageSizeMargins;
class PrepareFrameAndViewForPrint;
// Stores reference to frame using WebVew and unique name.
// Workaround to modal dialog issue on Linux. crbug.com/236147.
// If WebFrame someday supports WeakPtr, we should use it here.
class FrameReference {
public:
explicit FrameReference(blink::WebLocalFrame* frame);
FrameReference();
~FrameReference();
void Reset(blink::WebLocalFrame* frame);
blink::WebLocalFrame* GetFrame();
blink::WebView* view();
private:
blink::WebView* view_;
blink::WebLocalFrame* frame_;
};
// PrintWebViewHelper handles most of the printing grunt work for RenderView.
// We plan on making print asynchronous and that will require copying the DOM
// of the document and creating a new WebView with the contents.
class PrintWebViewHelper
: public content::RenderViewObserver,
public content::RenderViewObserverTracker<PrintWebViewHelper> {
public:
explicit PrintWebViewHelper(content::RenderView* render_view);
virtual ~PrintWebViewHelper();
void PrintNode(const blink::WebNode& node);
private:
enum PrintingResult {
OK,
FAIL_PRINT_INIT,
FAIL_PRINT,
};
// RenderViewObserver implementation.
virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
virtual void PrintPage(blink::WebLocalFrame* frame,
bool user_initiated) OVERRIDE;
// Message handlers ---------------------------------------------------------
void OnPrintPages(bool silent, bool print_background);
void OnPrintingDone(bool success);
// Get |page_size| and |content_area| information from
// |page_layout_in_points|.
void GetPageSizeAndContentAreaFromPageLayout(
const PageSizeMargins& page_layout_in_points,
gfx::Size* page_size,
gfx::Rect* content_area);
// Update |ignore_css_margins_| based on settings.
void UpdateFrameMarginsCssInfo(const base::DictionaryValue& settings);
// Main printing code -------------------------------------------------------
void Print(blink::WebLocalFrame* frame,
const blink::WebNode& node,
bool silent = false,
bool print_background = false);
// Notification when printing is done - signal tear-down/free resources.
void DidFinishPrinting(PrintingResult result);
// Print Settings -----------------------------------------------------------
// Initialize print page settings with default settings.
// Used only for native printing workflow.
bool InitPrintSettings(bool fit_to_paper_size);
// Calculate number of pages in source document.
bool CalculateNumberOfPages(blink::WebLocalFrame* frame,
const blink::WebNode& node,
int* number_of_pages);
// Get final print settings from the user.
// Return false if the user cancels or on error.
bool GetPrintSettingsFromUser(blink::WebFrame* frame,
const blink::WebNode& node,
int expected_pages_count);
// Page Printing / Rendering ------------------------------------------------
void OnFramePreparedForPrintPages();
void PrintPages();
bool PrintPagesNative(blink::WebFrame* frame,
int page_count,
const gfx::Size& canvas_size);
void FinishFramePrinting();
// Prints the page listed in |params|.
#if defined(OS_LINUX) || defined(OS_ANDROID)
void PrintPageInternal(const PrintMsg_PrintPage_Params& params,
const gfx::Size& canvas_size,
blink::WebFrame* frame,
Metafile* metafile);
#else
void PrintPageInternal(const PrintMsg_PrintPage_Params& params,
const gfx::Size& canvas_size,
blink::WebFrame* frame);
#endif
// Render the frame for printing.
bool RenderPagesForPrint(blink::WebLocalFrame* frame,
const blink::WebNode& node);
// Platform specific helper function for rendering page(s) to |metafile|.
#if defined(OS_WIN)
void RenderPage(const PrintMsg_Print_Params& params,
int page_number,
blink::WebFrame* frame,
bool is_preview,
Metafile* metafile,
double* scale_factor,
gfx::Size* page_size_in_dpi,
gfx::Rect* content_area_in_dpi);
#elif defined(OS_MACOSX)
void RenderPage(const PrintMsg_Print_Params& params,
int page_number,
blink::WebFrame* frame,
bool is_preview,
Metafile* metafile,
gfx::Size* page_size,
gfx::Rect* content_rect);
#endif // defined(OS_WIN)
// Renders page contents from |frame| to |content_area| of |canvas|.
// |page_number| is zero-based.
// When method is called, canvas should be setup to draw to |canvas_area|
// with |scale_factor|.
static float RenderPageContent(blink::WebFrame* frame,
int page_number,
const gfx::Rect& canvas_area,
const gfx::Rect& content_area,
double scale_factor,
blink::WebCanvas* canvas);
// Helper methods -----------------------------------------------------------
bool CopyMetafileDataToSharedMem(Metafile* metafile,
base::SharedMemoryHandle* shared_mem_handle);
// Helper method to get page layout in points and fit to page if needed.
static void ComputePageLayoutInPointsForCss(
blink::WebFrame* frame,
int page_index,
const PrintMsg_Print_Params& default_params,
bool ignore_css_margins,
double* scale_factor,
PageSizeMargins* page_layout_in_points);
bool GetPrintFrame(blink::WebLocalFrame** frame);
// Script Initiated Printing ------------------------------------------------
// WebView used only to print the selection.
scoped_ptr<PrepareFrameAndViewForPrint> prep_frame_view_;
scoped_ptr<PrintMsg_PrintPages_Params> print_pages_params_;
bool is_print_ready_metafile_sent_;
bool ignore_css_margins_;
// Let the browser process know of a printing failure. Only set to false when
// the failure came from the browser in the first place.
bool notify_browser_of_print_failure_;
bool print_node_in_progress_;
base::WeakPtrFactory<PrintWebViewHelper> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(PrintWebViewHelper);
};
} // namespace printing
#endif // CHROME_RENDERER_PRINTING_PRINT_WEB_VIEW_HELPER_H_

View file

@ -0,0 +1,157 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/renderer/printing/print_web_view_helper.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "chrome/common/print_messages.h"
#include "content/public/renderer/render_thread.h"
#include "printing/metafile.h"
#include "printing/metafile_impl.h"
#include "printing/metafile_skia_wrapper.h"
#include "printing/page_size_margins.h"
#include "skia/ext/platform_device.h"
#include "skia/ext/vector_canvas.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
#include "base/process/process_handle.h"
#else
#include "base/file_descriptor_posix.h"
#endif // !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
namespace printing {
using blink::WebFrame;
bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame,
int page_count,
const gfx::Size& canvas_size) {
NativeMetafile metafile;
if (!metafile.Init())
return false;
const PrintMsg_PrintPages_Params& params = *print_pages_params_;
std::vector<int> printed_pages;
if (params.pages.empty()) {
for (int i = 0; i < page_count; ++i) {
printed_pages.push_back(i);
}
} else {
// TODO(vitalybuka): redesign to make more code cross platform.
for (size_t i = 0; i < params.pages.size(); ++i) {
if (params.pages[i] >= 0 && params.pages[i] < page_count) {
printed_pages.push_back(params.pages[i]);
}
}
}
if (printed_pages.empty())
return false;
PrintMsg_PrintPage_Params page_params;
page_params.params = params.params;
for (size_t i = 0; i < printed_pages.size(); ++i) {
page_params.page_number = printed_pages[i];
PrintPageInternal(page_params, canvas_size, frame, &metafile);
}
// blink::printEnd() for PDF should be called before metafile is closed.
FinishFramePrinting();
metafile.FinishDocument();
// Get the size of the resulting metafile.
uint32 buf_size = metafile.GetDataSize();
DCHECK_GT(buf_size, 0u);
#if defined(OS_CHROMEOS) || defined(OS_ANDROID)
int sequence_number = -1;
base::FileDescriptor fd;
// Ask the browser to open a file for us.
Send(new PrintHostMsg_AllocateTempFileForPrinting(routing_id(),
&fd,
&sequence_number));
if (!metafile.SaveToFD(fd))
return false;
// Tell the browser we've finished writing the file.
Send(new PrintHostMsg_TempFileForPrintingWritten(routing_id(),
sequence_number));
return true;
#else
PrintHostMsg_DidPrintPage_Params printed_page_params;
printed_page_params.data_size = 0;
printed_page_params.document_cookie = params.params.document_cookie;
{
scoped_ptr<base::SharedMemory> shared_mem(
content::RenderThread::Get()->HostAllocateSharedMemoryBuffer(
buf_size).release());
if (!shared_mem.get()) {
NOTREACHED() << "AllocateSharedMemoryBuffer failed";
return false;
}
if (!shared_mem->Map(buf_size)) {
NOTREACHED() << "Map failed";
return false;
}
metafile.GetData(shared_mem->memory(), buf_size);
printed_page_params.data_size = buf_size;
shared_mem->GiveToProcess(base::GetCurrentProcessHandle(),
&(printed_page_params.metafile_data_handle));
}
for (size_t i = 0; i < printed_pages.size(); ++i) {
printed_page_params.page_number = printed_pages[i];
Send(new PrintHostMsg_DidPrintPage(routing_id(), printed_page_params));
// Send the rest of the pages with an invalid metafile handle.
printed_page_params.metafile_data_handle.fd = -1;
}
return true;
#endif // defined(OS_CHROMEOS)
}
void PrintWebViewHelper::PrintPageInternal(
const PrintMsg_PrintPage_Params& params,
const gfx::Size& canvas_size,
WebFrame* frame,
Metafile* metafile) {
PageSizeMargins page_layout_in_points;
double scale_factor = 1.0f;
ComputePageLayoutInPointsForCss(frame, params.page_number, params.params,
ignore_css_margins_, &scale_factor,
&page_layout_in_points);
gfx::Size page_size;
gfx::Rect content_area;
GetPageSizeAndContentAreaFromPageLayout(page_layout_in_points, &page_size,
&content_area);
gfx::Rect canvas_area = content_area;
SkBaseDevice* device = metafile->StartPageForVectorCanvas(page_size,
canvas_area,
scale_factor);
if (!device)
return;
// The printPage method take a reference to the canvas we pass down, so it
// can't be a stack object.
skia::RefPtr<skia::VectorCanvas> canvas =
skia::AdoptRef(new skia::VectorCanvas(device));
MetafileSkiaWrapper::SetMetafileOnCanvas(*canvas, metafile);
skia::SetIsDraftMode(*canvas, is_print_ready_metafile_sent_);
RenderPageContent(frame, params.page_number, canvas_area, content_area,
scale_factor, canvas.get());
// Done printing. Close the device context to retrieve the compiled metafile.
if (!metafile->FinishPage())
NOTREACHED() << "metafile failed";
}
} // namespace printing

View file

@ -0,0 +1,99 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/renderer/printing/print_web_view_helper.h"
#import <AppKit/AppKit.h>
#include "base/logging.h"
#include "base/mac/scoped_nsautorelease_pool.h"
#include "base/metrics/histogram.h"
#include "chrome/common/print_messages.h"
#include "printing/metafile.h"
#include "printing/metafile_impl.h"
#include "printing/metafile_skia_wrapper.h"
#include "printing/page_size_margins.h"
#include "skia/ext/platform_device.h"
#include "skia/ext/vector_canvas.h"
#include "third_party/WebKit/public/platform/WebCanvas.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
namespace printing {
using blink::WebFrame;
void PrintWebViewHelper::PrintPageInternal(
const PrintMsg_PrintPage_Params& params,
const gfx::Size& canvas_size,
WebFrame* frame) {
NativeMetafile metafile;
if (!metafile.Init())
return;
int page_number = params.page_number;
gfx::Size page_size_in_dpi;
gfx::Rect content_area_in_dpi;
RenderPage(print_pages_params_->params, page_number, frame, false, &metafile,
&page_size_in_dpi, &content_area_in_dpi);
metafile.FinishDocument();
PrintHostMsg_DidPrintPage_Params page_params;
page_params.data_size = metafile.GetDataSize();
page_params.page_number = page_number;
page_params.document_cookie = params.params.document_cookie;
page_params.page_size = page_size_in_dpi;
page_params.content_area = content_area_in_dpi;
// Ask the browser to create the shared memory for us.
if (!CopyMetafileDataToSharedMem(&metafile,
&(page_params.metafile_data_handle))) {
page_params.data_size = 0;
}
Send(new PrintHostMsg_DidPrintPage(routing_id(), page_params));
}
void PrintWebViewHelper::RenderPage(
const PrintMsg_Print_Params& params, int page_number, WebFrame* frame,
bool is_preview, Metafile* metafile, gfx::Size* page_size,
gfx::Rect* content_rect) {
double scale_factor = 1.0f;
double webkit_shrink_factor = frame->getPrintPageShrink(page_number);
PageSizeMargins page_layout_in_points;
gfx::Rect content_area;
ComputePageLayoutInPointsForCss(frame, page_number, params,
ignore_css_margins_, &scale_factor,
&page_layout_in_points);
GetPageSizeAndContentAreaFromPageLayout(page_layout_in_points, page_size,
&content_area);
if (content_rect)
*content_rect = content_area;
scale_factor *= webkit_shrink_factor;
gfx::Rect canvas_area = content_area;
{
SkBaseDevice* device = metafile->StartPageForVectorCanvas(
*page_size, canvas_area, scale_factor);
if (!device)
return;
skia::RefPtr<skia::VectorCanvas> canvas =
skia::AdoptRef(new skia::VectorCanvas(device));
blink::WebCanvas* canvas_ptr = canvas.get();
MetafileSkiaWrapper::SetMetafileOnCanvas(*canvas, metafile);
skia::SetIsDraftMode(*canvas, is_print_ready_metafile_sent_);
skia::SetIsPreviewMetafile(*canvas, is_preview);
RenderPageContent(frame, page_number, canvas_area, content_area,
scale_factor, canvas_ptr);
}
// Done printing. Close the device context to retrieve the compiled metafile.
metafile->FinishPage();
}
} // namespace printing

View file

@ -0,0 +1,193 @@
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/renderer/printing/print_web_view_helper.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/metrics/histogram.h"
#include "base/process/process_handle.h"
#include "base/win/scoped_gdi_object.h"
#include "base/win/scoped_hdc.h"
#include "base/win/scoped_select_object.h"
#include "chrome/common/print_messages.h"
#include "printing/metafile.h"
#include "printing/metafile_impl.h"
#include "printing/metafile_skia_wrapper.h"
#include "printing/page_size_margins.h"
#include "printing/units.h"
#include "skia/ext/platform_device.h"
#include "skia/ext/refptr.h"
#include "skia/ext/vector_canvas.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "ui/gfx/gdi_util.h"
#include "ui/gfx/point.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
namespace printing {
using blink::WebFrame;
void PrintWebViewHelper::PrintPageInternal(
const PrintMsg_PrintPage_Params& params,
const gfx::Size& canvas_size,
WebFrame* frame) {
// Generate a memory-based metafile. It will use the current screen's DPI.
// Each metafile contains a single page.
scoped_ptr<NativeMetafile> metafile(new NativeMetafile);
metafile->Init();
DCHECK(metafile->context());
skia::InitializeDC(metafile->context());
int page_number = params.page_number;
// Calculate the dpi adjustment.
// Browser will render context using desired_dpi, so we need to calculate
// adjustment factor to play content on the printer DC later during the
// actual printing.
double actual_shrink = static_cast<float>(params.params.desired_dpi /
params.params.dpi);
gfx::Size page_size_in_dpi;
gfx::Rect content_area_in_dpi;
// Render page for printing.
RenderPage(params.params, page_number, frame, false, metafile.get(),
&actual_shrink, &page_size_in_dpi, &content_area_in_dpi);
// Close the device context to retrieve the compiled metafile.
if (!metafile->FinishDocument())
NOTREACHED();
if (!params.params.supports_alpha_blend && metafile->IsAlphaBlendUsed()) {
scoped_ptr<NativeMetafile> raster_metafile(
metafile->RasterizeAlphaBlend());
if (raster_metafile.get())
metafile.swap(raster_metafile);
}
// Get the size of the compiled metafile.
uint32 buf_size = metafile->GetDataSize();
DCHECK_GT(buf_size, 128u);
PrintHostMsg_DidPrintPage_Params page_params;
page_params.data_size = buf_size;
page_params.metafile_data_handle = NULL;
page_params.page_number = page_number;
page_params.document_cookie = params.params.document_cookie;
page_params.actual_shrink = actual_shrink;
page_params.page_size = page_size_in_dpi;
page_params.content_area = content_area_in_dpi;
if (!CopyMetafileDataToSharedMem(metafile.get(),
&(page_params.metafile_data_handle))) {
page_params.data_size = 0;
}
Send(new PrintHostMsg_DidPrintPage(routing_id(), page_params));
}
void PrintWebViewHelper::RenderPage(
const PrintMsg_Print_Params& params, int page_number, WebFrame* frame,
bool is_preview, Metafile* metafile, double* actual_shrink,
gfx::Size* page_size_in_dpi, gfx::Rect* content_area_in_dpi) {
PageSizeMargins page_layout_in_points;
double css_scale_factor = 1.0f;
ComputePageLayoutInPointsForCss(frame, page_number, params,
ignore_css_margins_, &css_scale_factor,
&page_layout_in_points);
gfx::Size page_size;
gfx::Rect content_area;
GetPageSizeAndContentAreaFromPageLayout(page_layout_in_points, &page_size,
&content_area);
int dpi = static_cast<int>(params.dpi);
// Calculate the actual page size and content area in dpi.
if (page_size_in_dpi) {
*page_size_in_dpi = gfx::Size(
static_cast<int>(ConvertUnitDouble(page_size.width(), kPointsPerInch,
dpi)),
static_cast<int>(ConvertUnitDouble(page_size.height(), kPointsPerInch,
dpi)));
}
if (content_area_in_dpi) {
*content_area_in_dpi = gfx::Rect(
static_cast<int>(ConvertUnitDouble(content_area.x(), kPointsPerInch,
dpi)),
static_cast<int>(ConvertUnitDouble(content_area.y(), kPointsPerInch,
dpi)),
static_cast<int>(ConvertUnitDouble(content_area.width(), kPointsPerInch,
dpi)),
static_cast<int>(ConvertUnitDouble(content_area.height(),
kPointsPerInch, dpi)));
}
float webkit_page_shrink_factor = frame->getPrintPageShrink(page_number);
float scale_factor = css_scale_factor * webkit_page_shrink_factor;
gfx::Rect canvas_area = content_area;
SkBaseDevice* device = metafile->StartPageForVectorCanvas(
page_size, canvas_area, scale_factor);
DCHECK(device);
// The printPage method may take a reference to the canvas we pass down, so it
// can't be a stack object.
skia::RefPtr<skia::VectorCanvas> canvas =
skia::AdoptRef(new skia::VectorCanvas(device));
float webkit_scale_factor = RenderPageContent(frame, page_number, canvas_area,
content_area, scale_factor,
canvas.get());
if (*actual_shrink <= 0 || webkit_scale_factor <= 0) {
NOTREACHED() << "Printing page " << page_number << " failed.";
} else {
// While rendering certain plugins (PDF) to metafile, we might need to
// set custom scale factor. Update |actual_shrink| with custom scale
// if it is set on canvas.
// TODO(gene): We should revisit this solution for the next versions.
// Consider creating metafile of the right size (or resizable)
// https://code.google.com/p/chromium/issues/detail?id=126037
if (!MetafileSkiaWrapper::GetCustomScaleOnCanvas(
*canvas, actual_shrink)) {
// Update the dpi adjustment with the "page |actual_shrink|" calculated in
// webkit.
*actual_shrink /= (webkit_scale_factor * css_scale_factor);
}
}
bool result = metafile->FinishPage();
DCHECK(result);
}
bool PrintWebViewHelper::CopyMetafileDataToSharedMem(
Metafile* metafile, base::SharedMemoryHandle* shared_mem_handle) {
uint32 buf_size = metafile->GetDataSize();
base::SharedMemory shared_buf;
if (buf_size >= kMetafileMaxSize) {
NOTREACHED() << "Buffer too large: " << buf_size;
return false;
}
// Allocate a shared memory buffer to hold the generated metafile data.
if (!shared_buf.CreateAndMapAnonymous(buf_size)) {
NOTREACHED() << "Buffer allocation failed";
return false;
}
// Copy the bits into shared memory.
if (!metafile->GetData(shared_buf.memory(), buf_size)) {
NOTREACHED() << "GetData() failed";
shared_buf.Unmap();
return false;
}
shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), shared_mem_handle);
shared_buf.Unmap();
Send(new PrintHostMsg_DuplicateSection(routing_id(), *shared_mem_handle,
shared_mem_handle));
return true;
}
} // namespace printing

View file

View file

@ -338,7 +338,7 @@ Changes the title of native window to `title`.
Returns the title of the native window.
**Note:** The title of web page can be different from the title of the native
**window.
window.
### BrowserWindow.flashFrame()
@ -408,10 +408,10 @@ Starts inspecting element at position (`x`, `y`).
### BrowserWindow.capturePage([rect, ]callback)
* `rect` Object - The area of page to be captured
* `x`
* `y`
* `width`
* `height`
* `x` Integer
* `y` Integer
* `width` Integer
* `height` Integer
* `callback` Function
Captures the snapshot of page within `rect`, upon completion `callback` would be
@ -426,6 +426,19 @@ encode it and use data URL to embed the image in HTML.
[remote](remote.md) if you are going to use this API in renderer
process.
### BrowserWindow.print([options])
* `options` Object
* `silent` Boolean - Don't ask user for print settings, defaults to `false`
* `printBackground` Boolean - Also prints the background color and image of
the web page, defaults to `false`.
Prints window's web page. When `silent` is set to `false`, atom-shell will pick
up system's default printer and default settings for printing.
Calling `window.print()` in web page is equivalent to call
`BrowserWindow.print({silent: false, printBackground: false})`.
### BrowserWindow.loadUrl(url)
Same with `webContents.loadUrl(url)`.

3
script/cpplint.py vendored
View file

@ -16,10 +16,11 @@ IGNORE_FILES = [
os.path.join('atom', 'browser', 'ui', 'cocoa', 'atom_menu_controller.h'),
os.path.join('atom', 'browser', 'ui', 'gtk', 'gtk_custom_menu.cc'),
os.path.join('atom', 'browser', 'ui', 'gtk', 'gtk_custom_menu_item.cc'),
os.path.join('atom', 'common', 'api', 'api_messages.cc'),
os.path.join('atom', 'common', 'api', 'api_messages.h'),
os.path.join('atom', 'common', 'api', 'atom_extensions.h'),
os.path.join('atom', 'common', 'atom_version.h'),
os.path.join('atom', 'common', 'common_message_generator.cc'),
os.path.join('atom', 'common', 'common_message_generator.h'),
os.path.join('atom', 'common', 'swap_or_assign.h'),
]

View file

@ -5,7 +5,7 @@ import sys
NODE_VERSION = 'v0.11.13'
BASE_URL = 'https://gh-contractor-zcbenz.s3.amazonaws.com/libchromiumcontent'
LIBCHROMIUMCONTENT_COMMIT = 'bb664e4665851fe923ce904e620ba43d8d010ba5'
LIBCHROMIUMCONTENT_COMMIT = '432720d4613e3aac939f127fe55b9d44fea349e5'
ARCH = {
'cygwin': '32bit',