blob: 058b754bae476f28b7a99e847af1372c1b171131 [file] [log] [blame]
// 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/background_printing_manager.h"
#include "chrome/browser/printing/print_job.h"
#include "chrome/browser/printing/print_preview_tab_controller.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/tab_contents/tab_contents.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_notification_types.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
using content::BrowserThread;
using content::WebContents;
namespace printing {
BackgroundPrintingManager::BackgroundPrintingManager() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}
BackgroundPrintingManager::~BackgroundPrintingManager() {
DCHECK(CalledOnValidThread());
// The might be some TabContents still in |printing_tabs_| at
// this point. E.g. when the last remaining tab is a print preview tab and
// tries to print. In which case it will fail to print.
// TODO(thestig) handle this case better.
}
void BackgroundPrintingManager::OwnPrintPreviewTab(TabContents* preview_tab) {
DCHECK(CalledOnValidThread());
DCHECK(PrintPreviewTabController::IsPrintPreviewTab(preview_tab));
CHECK(!HasPrintPreviewTab(preview_tab));
printing_tabs_.insert(preview_tab);
content::Source<TabContents> preview_source(preview_tab);
registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED, preview_source);
// OwnInitiatorTabContents() may have already added this notification.
if (!registrar_.IsRegistered(this,
chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED, preview_source)) {
registrar_.Add(this, chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED,
preview_source);
}
// If a tab that is printing crashes, the user cannot destroy it since it is
// not in any tab strip. Thus listen for crashes here and delete the tab.
//
// Multiple sites may share the same RenderProcessHost, so check if this
// notification has already been added.
content::Source<content::RenderProcessHost> rph_source(
preview_tab->web_contents()->GetRenderProcessHost());
if (!registrar_.IsRegistered(this,
content::NOTIFICATION_RENDERER_PROCESS_CLOSED, rph_source)) {
registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
rph_source);
}
// Activate the initiator tab.
PrintPreviewTabController* tab_controller =
PrintPreviewTabController::GetInstance();
if (!tab_controller)
return;
TabContents* initiator_tab = tab_controller->GetInitiatorTab(preview_tab);
if (!initiator_tab)
return;
WebContents* web_contents = initiator_tab->web_contents();
web_contents->GetDelegate()->ActivateContents(web_contents);
}
void BackgroundPrintingManager::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
if (type == content::NOTIFICATION_RENDERER_PROCESS_CLOSED) {
OnRendererProcessClosed(
content::Source<content::RenderProcessHost>(source).ptr());
} else if (type == chrome::NOTIFICATION_PRINT_JOB_RELEASED) {
OnPrintJobReleased(content::Source<TabContents>(source).ptr());
} else {
DCHECK_EQ(chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED, type);
OnTabContentsDestroyed(content::Source<TabContents>(source).ptr());
}
}
void BackgroundPrintingManager::OnRendererProcessClosed(
content::RenderProcessHost* rph) {
TabContentsSet preview_tabs_pending_deletion;
TabContentsSet::const_iterator it;
for (it = begin(); it != end(); ++it) {
TabContents* preview_tab = *it;
if (preview_tab->web_contents()->GetRenderProcessHost() == rph) {
preview_tabs_pending_deletion.insert(preview_tab);
}
}
for (it = preview_tabs_pending_deletion.begin();
it != preview_tabs_pending_deletion.end();
++it) {
DeletePreviewTab(*it);
}
}
void BackgroundPrintingManager::OnPrintJobReleased(TabContents* preview_tab) {
DeletePreviewTab(preview_tab);
}
void BackgroundPrintingManager::OnTabContentsDestroyed(
TabContents* preview_tab) {
// Always need to remove this notification since the tab is gone.
content::Source<TabContents> preview_source(preview_tab);
registrar_.Remove(this, chrome::NOTIFICATION_TAB_CONTENTS_DESTROYED,
preview_source);
if (!HasPrintPreviewTab(preview_tab)) {
NOTREACHED();
return;
}
// Remove NOTIFICATION_RENDERER_PROCESS_CLOSED if |preview_tab| is the last
// WebContents associated with |rph|.
bool shared_rph = HasSharedRenderProcessHost(printing_tabs_, preview_tab) ||
HasSharedRenderProcessHost(printing_tabs_pending_deletion_, preview_tab);
if (!shared_rph) {
content::RenderProcessHost* rph =
preview_tab->web_contents()->GetRenderProcessHost();
registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
content::Source<content::RenderProcessHost>(rph));
}
// Remove other notifications and remove the tab from its TabContentsSet.
if (printing_tabs_.find(preview_tab) != printing_tabs_.end()) {
registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED,
preview_source);
printing_tabs_.erase(preview_tab);
} else {
// DeletePreviewTab already deleted the notification.
printing_tabs_pending_deletion_.erase(preview_tab);
}
}
void BackgroundPrintingManager::DeletePreviewTab(TabContents* tab) {
registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED,
content::Source<TabContents>(tab));
printing_tabs_.erase(tab);
printing_tabs_pending_deletion_.insert(tab);
MessageLoop::current()->DeleteSoon(FROM_HERE, tab);
}
bool BackgroundPrintingManager::HasSharedRenderProcessHost(
const TabContentsSet& set,
TabContents* tab) {
content::RenderProcessHost* rph = tab->web_contents()->GetRenderProcessHost();
for (TabContentsSet::const_iterator it = set.begin(); it != set.end(); ++it) {
TabContents* iter_tab = *it;
if ((iter_tab != tab) &&
(iter_tab->web_contents()->GetRenderProcessHost() == rph)) {
return true;
}
}
return false;
}
BackgroundPrintingManager::TabContentsSet::const_iterator
BackgroundPrintingManager::begin() {
return printing_tabs_.begin();
}
BackgroundPrintingManager::TabContentsSet::const_iterator
BackgroundPrintingManager::end() {
return printing_tabs_.end();
}
bool BackgroundPrintingManager::HasPrintPreviewTab(
TabContents* preview_tab) {
if (printing_tabs_.find(preview_tab) != printing_tabs_.end())
return true;
return printing_tabs_pending_deletion_.find(preview_tab) !=
printing_tabs_pending_deletion_.end();
}
} // namespace printing