summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/printing/background_printing_manager.cc177
-rw-r--r--chrome/browser/printing/background_printing_manager.h27
-rw-r--r--chrome/browser/ui/browser.cc14
3 files changed, 192 insertions, 26 deletions
diff --git a/chrome/browser/printing/background_printing_manager.cc b/chrome/browser/printing/background_printing_manager.cc
index 01f3d36..f1e9c24 100644
--- a/chrome/browser/printing/background_printing_manager.cc
+++ b/chrome/browser/printing/background_printing_manager.cc
@@ -12,6 +12,7 @@
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/chrome_notification_types.h"
#include "content/browser/browser_thread.h"
+#include "content/browser/renderer_host/render_view_host.h"
#include "content/common/notification_details.h"
#include "content/common/notification_source.h"
@@ -33,22 +34,36 @@ void BackgroundPrintingManager::OwnPrintPreviewTab(
TabContentsWrapper* preview_tab) {
DCHECK(CalledOnValidThread());
DCHECK(PrintPreviewTabController::IsPrintPreviewTab(preview_tab));
- CHECK(printing_tabs_.find(preview_tab) == printing_tabs_.end());
+ CHECK(!HasPrintPreviewTab(preview_tab));
printing_tabs_.insert(preview_tab);
registrar_.Add(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED,
Source<TabContentsWrapper>(preview_tab));
- registrar_.Add(this, content::NOTIFICATION_TAB_CONTENTS_DESTROYED,
- Source<TabContents>(preview_tab->tab_contents()));
- // Detach |preview_tab| from its tab strip.
- Browser* browser = BrowserList::FindBrowserWithID(
- preview_tab->restore_tab_helper()->window_id().id());
- DCHECK(browser);
+ // OwnInitiatorTabContents() may have already added this notification.
+ TabContents* preview_contents = preview_tab->tab_contents();
+ if (!registrar_.IsRegistered(this,
+ content::NOTIFICATION_TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(preview_contents))) {
+ registrar_.Add(this, content::NOTIFICATION_TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(preview_contents));
+ }
- TabStripModel* tabstrip = browser->tabstrip_model();
- tabstrip->DetachTabContentsAt(tabstrip->GetIndexOfTabContents(preview_tab));
+ // 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.
+ RenderProcessHost* rph = preview_tab->render_view_host()->process();
+ if (!registrar_.IsRegistered(this,
+ content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
+ Source<RenderProcessHost>(rph))) {
+ registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
+ Source<RenderProcessHost>(rph));
+ }
+
+ RemoveFromTabStrip(preview_tab);
// Activate the initiator tab.
PrintPreviewTabController* tab_controller =
@@ -63,32 +78,60 @@ void BackgroundPrintingManager::OwnPrintPreviewTab(
initiator_tab->tab_contents())->Activate();
}
+bool BackgroundPrintingManager::OwnInitiatorTab(
+ TabContentsWrapper* initiator_tab) {
+ DCHECK(CalledOnValidThread());
+ DCHECK(!PrintPreviewTabController::IsPrintPreviewTab(initiator_tab));
+ bool has_initiator_tab = false;
+ for (TabContentsWrapperMap::iterator it = map_.begin(); it != map_.end();
+ ++it) {
+ if (it->second == initiator_tab) {
+ has_initiator_tab = true;
+ break;
+ }
+ }
+ CHECK(!has_initiator_tab);
+
+ PrintPreviewTabController* tab_controller =
+ PrintPreviewTabController::GetInstance();
+ if (!tab_controller)
+ return false;
+ TabContentsWrapper* preview_tab =
+ tab_controller->GetPrintPreviewForTab(initiator_tab);
+ if (!preview_tab)
+ return false;
+
+ map_[preview_tab] = initiator_tab;
+
+ // OwnPrintPreviewTab() may have already added this notification.
+ TabContents* preview_contents = preview_tab->tab_contents();
+ if (!registrar_.IsRegistered(this,
+ content::NOTIFICATION_TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(preview_contents))) {
+ registrar_.Add(this, content::NOTIFICATION_TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(preview_contents));
+ }
+
+ RemoveFromTabStrip(initiator_tab);
+ return true;
+}
+
void BackgroundPrintingManager::Observe(int type,
const NotificationSource& source,
const NotificationDetails& details) {
switch (type) {
+ case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
+ OnRendererProcessClosed(Source<RenderProcessHost>(source).ptr());
+ break;
+ }
case chrome::NOTIFICATION_PRINT_JOB_RELEASED: {
- TabContentsWrapper* tab = Source<TabContentsWrapper>(source).ptr();
- registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED,
- Source<TabContentsWrapper>(tab));
-
- // This might be happening in the middle of a RenderViewGone() loop.
- // Deleting |contents| later so the RenderViewGone() loop can finish.
- MessageLoop::current()->DeleteSoon(FROM_HERE, tab);
+ OnPrintJobReleased(Source<TabContentsWrapper>(source).ptr());
break;
}
case content::NOTIFICATION_TAB_CONTENTS_DESTROYED: {
- TabContentsWrapper* tab =
+ OnTabContentsDestroyed(
TabContentsWrapper::GetCurrentWrapperForContents(
- Source<TabContents>(source).ptr());
- if (registrar_.IsRegistered(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED,
- Source<TabContentsWrapper>(tab))) {
- registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED,
- Source<TabContentsWrapper>(tab));
- }
- registrar_.Remove(this, content::NOTIFICATION_TAB_CONTENTS_DESTROYED,
- Source<TabContents>(tab->tab_contents()));
- printing_tabs_.erase(tab);
+ Source<TabContents>(source).ptr()));
break;
}
default: {
@@ -98,6 +141,88 @@ void BackgroundPrintingManager::Observe(int type,
}
}
+void BackgroundPrintingManager::OnRendererProcessClosed(
+ RenderProcessHost* rph) {
+ TabContentsWrapperSet::const_iterator it;
+ for (it = begin(); it != end(); ++it) {
+ TabContentsWrapper* tab = *it;
+ if (tab->render_view_host()->process() == rph)
+ MessageLoop::current()->DeleteSoon(FROM_HERE, tab);
+ }
+}
+
+void BackgroundPrintingManager::OnPrintJobReleased(
+ TabContentsWrapper* preview_tab) {
+ registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED,
+ Source<TabContentsWrapper>(preview_tab));
+
+ // This might be happening in the middle of a RenderViewGone() loop.
+ // Deleting |contents| later so the RenderViewGone() loop can finish.
+ MessageLoop::current()->DeleteSoon(FROM_HERE, preview_tab);
+}
+
+void BackgroundPrintingManager::OnTabContentsDestroyed(
+ TabContentsWrapper* preview_tab) {
+ bool is_owned_printing_tab = HasPrintPreviewTab(preview_tab);
+ bool is_preview_tab_for_owned_initator_tab =
+ (map_.find(preview_tab) != map_.end());
+ DCHECK(is_owned_printing_tab || is_preview_tab_for_owned_initator_tab);
+
+ // Always need to remove this notification since the tab is gone.
+ registrar_.Remove(this, content::NOTIFICATION_TAB_CONTENTS_DESTROYED,
+ Source<TabContents>(preview_tab->tab_contents()));
+
+ // Delete the associated initiator tab if one exists.
+ if (is_preview_tab_for_owned_initator_tab) {
+ TabContentsWrapper* initiator_tab = map_[preview_tab];
+ map_.erase(preview_tab);
+ MessageLoop::current()->DeleteSoon(FROM_HERE, initiator_tab);
+ }
+
+ // If |preview_tab| is not owned, then we are done.
+ if (!is_owned_printing_tab)
+ return;
+
+ // Remove NOTIFICATION_RENDERER_PROCESS_CLOSED if |tab| is the last
+ // TabContents associated with |rph|.
+ bool shared_rph = false;
+ RenderProcessHost* rph = preview_tab->render_view_host()->process();
+ TabContentsWrapperSet::const_iterator it;
+ for (it = begin(); it != end(); ++it) {
+ TabContentsWrapper* iter_tab = *it;
+ if (iter_tab == preview_tab)
+ continue;
+ if (iter_tab->render_view_host()->process() == rph) {
+ shared_rph = true;
+ break;
+ }
+ }
+ if (!shared_rph) {
+ registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
+ Source<RenderProcessHost>(rph));
+ }
+
+ // Remove other notifications and remove the tab from |printing_tabs_|.
+ if (registrar_.IsRegistered(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED,
+ Source<TabContentsWrapper>(preview_tab))) {
+ registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED,
+ Source<TabContentsWrapper>(preview_tab));
+ }
+ printing_tabs_.erase(preview_tab);
+}
+
+void BackgroundPrintingManager::RemoveFromTabStrip(TabContentsWrapper* tab) {
+ Browser* browser = BrowserList::FindBrowserWithID(
+ tab->restore_tab_helper()->window_id().id());
+ DCHECK(browser);
+
+ TabStripModel* tabstrip = browser->tabstrip_model();
+ int index = tabstrip->GetIndexOfTabContents(tab);
+ if (index == TabStripModel::kNoTab)
+ return;
+ tabstrip->DetachTabContentsAt(index);
+}
+
BackgroundPrintingManager::TabContentsWrapperSet::const_iterator
BackgroundPrintingManager::begin() {
return printing_tabs_.begin();
diff --git a/chrome/browser/printing/background_printing_manager.h b/chrome/browser/printing/background_printing_manager.h
index e580ed7..2ac37c7 100644
--- a/chrome/browser/printing/background_printing_manager.h
+++ b/chrome/browser/printing/background_printing_manager.h
@@ -6,6 +6,7 @@
#define CHROME_BROWSER_PRINTING_BACKGROUND_PRINTING_MANAGER_H_
#pragma once
+#include <map>
#include <set>
#include "base/compiler_specific.h"
@@ -13,6 +14,7 @@
#include "content/common/notification_observer.h"
#include "content/common/notification_registrar.h"
+class RenderProcessHost;
class TabContentsWrapper;
namespace printing {
@@ -33,6 +35,13 @@ class BackgroundPrintingManager : public base::NonThreadSafe,
// hides it from the user.
void OwnPrintPreviewTab(TabContentsWrapper* preview_tab);
+ // Takes ownership of |initiator_tab| and deletes it when its preview tab is
+ // destroyed by either being canceled, closed or finishing printing. This
+ // removes the TabContentsWrapper from its TabStrip and hides it from the
+ // user. Returns true if content has an associated print preview tab,
+ // otherwise, returns false and does not take ownership of |initiator_tab|.
+ bool OwnInitiatorTab(TabContentsWrapper* initiator_tab);
+
// Let others iterate over the list of background printing tabs.
TabContentsWrapperSet::const_iterator begin();
TabContentsWrapperSet::const_iterator end();
@@ -46,9 +55,27 @@ class BackgroundPrintingManager : public base::NonThreadSafe,
const NotificationDetails& details) OVERRIDE;
private:
+ typedef std::map<TabContentsWrapper*, TabContentsWrapper*>
+ TabContentsWrapperMap;
+
+ // Notifications handlers.
+ void OnRendererProcessClosed(RenderProcessHost* rph);
+ void OnPrintJobReleased(TabContentsWrapper* preview_tab);
+ void OnTabContentsDestroyed(TabContentsWrapper* preview_tab);
+
+ // Removes |tab| from its tab strip.
+ void RemoveFromTabStrip(TabContentsWrapper* tab);
+
// The set of print preview tabs managed by BackgroundPrintingManager.
TabContentsWrapperSet printing_tabs_;
+ // 1:1 mapping between an initiator tab managed by BackgroundPrintingManager
+ // and its associated print preview tab. The print preview tab need not be in
+ // |printing_tabs_|.
+ // Key: print preview tab.
+ // Value: initiator tab.
+ TabContentsWrapperMap map_;
+
NotificationRegistrar registrar_;
DISALLOW_COPY_AND_ASSIGN(BackgroundPrintingManager);
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index b872b83..d5b0b2f 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -62,6 +62,7 @@
#include "chrome/browser/prefs/incognito_mode_prefs.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/prerender/prerender_tab_helper.h"
+#include "chrome/browser/printing/background_printing_manager.h"
#include "chrome/browser/printing/cloud_print/cloud_print_setup_flow.h"
#include "chrome/browser/printing/print_preview_tab_controller.h"
#include "chrome/browser/printing/print_view_manager.h"
@@ -3487,6 +3488,19 @@ void Browser::CloseContents(TabContents* source) {
return;
}
+ // Various sites have a pattern which open a new window with output formatted
+ // for printing, then include a print button, which does window.print();
+ // window.close(); An example is printing Virgin America boarding
+ // pass. Instead of closing, when a print tab is associated with this tab,
+ // tell the BackgroundPrintingManager to own it, which causes it to be
+ // hidden and eventually closed when the print window is closed.
+ TabContentsWrapper* source_wrapper =
+ TabContentsWrapper::GetCurrentWrapperForContents(source);
+ if (g_browser_process->background_printing_manager()->
+ OwnInitiatorTab(source_wrapper)) {
+ return;
+ }
+
int index = tab_handler_->GetTabStripModel()->GetWrapperIndex(source);
if (index == TabStripModel::kNoTab) {
NOTREACHED() << "CloseContents called for tab not in our strip";