summaryrefslogtreecommitdiffstats
path: root/chrome/browser/printing/background_printing_manager.cc
diff options
context:
space:
mode:
authorthestig@chromium.org <thestig@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-08 20:34:53 +0000
committerthestig@chromium.org <thestig@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-08 20:34:53 +0000
commita8dd6821b85865a7af7b5488c289d38c665f3833 (patch)
tree5c630660a4e05423b9e940004b4e3ebadcabde11 /chrome/browser/printing/background_printing_manager.cc
parentd33ed29955ac8892231bccbe80c8464803ba0bc5 (diff)
downloadchromium_src-a8dd6821b85865a7af7b5488c289d38c665f3833.zip
chromium_src-a8dd6821b85865a7af7b5488c289d38c665f3833.tar.gz
chromium_src-a8dd6821b85865a7af7b5488c289d38c665f3833.tar.bz2
Print Preview: Hold on to tabs that do window.print(); window.close() until print preview finishes.
BUG=87362 TEST=Create html file with window.print(); window.close(); and then print, cancel or close the print tab. Review URL: http://codereview.chromium.org/7800036 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@100235 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/printing/background_printing_manager.cc')
-rw-r--r--chrome/browser/printing/background_printing_manager.cc177
1 files changed, 151 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();